blob: ec2b1e7e2ad83a6a4e033d5125b295b2a2c44648 [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>
4493 typedef std::string my_string;
4494 inline uint32_t take_str(my_string a) {
4495 return a.size();
4496 }
4497 "};
4498 let rs = quote! {
4499 use ffi::ToCppString;
4500 assert_eq!(ffi::take_str("hello".into_cpp()), 5);
4501 };
4502 run_test("", hdr, rs, &["take_str"], &[]);
4503}
4504
4505#[test]
4506fn test_typedef_to_up_in_fn_call() {
4507 let hdr = indoc! {"
4508 #include <string>
4509 #include <memory>
4510 typedef std::unique_ptr<std::string> my_string;
4511 inline uint32_t take_str(my_string a) {
4512 return a->size();
4513 }
4514 "};
4515 let rs = quote! {
4516 use ffi::ToCppString;
4517 assert_eq!(ffi::take_str("hello".into_cpp()), 5);
4518 };
4519 run_test("", hdr, rs, &["take_str"], &[]);
4520}
4521
4522#[test]
4523fn test_typedef_in_pod_struct() {
4524 let hdr = indoc! {"
4525 #include <string>
4526 typedef uint32_t my_int;
4527 struct A {
4528 my_int a;
4529 };
4530 inline uint32_t take_a(A a) {
4531 return a.a;
4532 }
4533 "};
4534 let rs = quote! {
4535 let a = ffi::A {
4536 a: 32,
4537 };
4538 assert_eq!(ffi::take_a(a), 32);
4539 };
4540 run_test("", hdr, rs, &["take_a"], &["A"]);
4541}
4542
4543#[test]
4544fn test_cint_in_pod_struct() {
4545 let hdr = indoc! {"
4546 #include <string>
4547 struct A {
4548 int a;
4549 };
4550 inline uint32_t take_a(A a) {
4551 return a.a;
4552 }
4553 "};
4554 let rs = quote! {
4555 let a = ffi::A {
4556 a: 32,
4557 };
4558 assert_eq!(ffi::take_a(a), 32);
4559 };
4560 run_test("", hdr, rs, &["take_a"], &["A"]);
4561}
4562
4563#[test]
4564fn test_string_in_struct() {
4565 let hdr = indoc! {"
4566 #include <string>
4567 #include <memory>
4568 struct A {
4569 std::string a;
4570 };
4571 inline A make_a(std::string b) {
4572 A bob;
4573 bob.a = b;
4574 return bob;
4575 }
4576 inline uint32_t take_a(A a) {
4577 return a.a.size();
4578 }
4579 "};
4580 let rs = quote! {
4581 use ffi::ToCppString;
4582 assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
4583 };
4584 run_test("", hdr, rs, &["make_a", "take_a"], &[]);
4585}
4586
4587#[test]
4588#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
4589fn test_up_in_struct() {
4590 let hdr = indoc! {"
4591 #include <string>
4592 #include <memory>
4593 struct A {
4594 std::unique_ptr<std::string> a;
4595 };
4596 inline A make_a(std::string b) {
4597 A bob;
4598 bob.a = std::make_unique<std::string>(b);
4599 return bob;
4600 }
4601 inline uint32_t take_a(A a) {
4602 return a.a->size();
4603 }
4604 "};
4605 let rs = quote! {
4606 use ffi::ToCppString;
4607 assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
4608 };
4609 run_test("", hdr, rs, &["make_a", "take_a"], &[]);
4610}
4611
4612#[test]
4613fn test_typedef_to_std_in_struct() {
4614 let hdr = indoc! {"
4615 #include <string>
4616 typedef std::string my_string;
4617 struct A {
4618 my_string a;
4619 };
4620 inline A make_a(std::string b) {
4621 A bob;
4622 bob.a = b;
4623 return bob;
4624 }
4625 inline uint32_t take_a(A a) {
4626 return a.a.size();
4627 }
4628 "};
4629 let rs = quote! {
4630 use ffi::ToCppString;
4631 assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
4632 };
4633 run_test("", hdr, rs, &["make_a", "take_a"], &[]);
4634}
4635
4636#[test]
4637#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
4638fn test_typedef_to_up_in_struct() {
4639 let hdr = indoc! {"
4640 #include <string>
4641 #include <memory>
4642 typedef std::unique_ptr<std::string> my_string;
4643 struct A {
4644 my_string a;
4645 };
4646 inline A make_a(std::string b) {
4647 A bob;
4648 bob.a = std::make_unique<std::string>(b);
4649 return bob;
4650 }
4651 inline uint32_t take_a(A a) {
4652 return a.a->size();
4653 }
4654 "};
4655 let rs = quote! {
4656 use ffi::ToCppString;
4657 assert_eq!(ffi::take_a(as_new(ffi::make_a("hello".into_cpp()))), 5);
4658 };
4659 run_test("", hdr, rs, &["make_a", "take_a"], &[]);
4660}
4661
4662#[test]
4663fn test_float() {
4664 let hdr = indoc! {"
4665 inline float daft(float a) { return a; }
4666 "};
4667 let rs = quote! {
4668 assert_eq!(ffi::daft(34.0f32), 34.0f32);
4669 };
4670 run_test("", hdr, rs, &["daft"], &[]);
4671}
4672
4673#[test]
4674fn test_double() {
4675 let hdr = indoc! {"
4676 inline double daft(double a) { return a; }
4677 "};
4678 let rs = quote! {
4679 assert_eq!(ffi::daft(34.0f64), 34.0f64);
4680 };
4681 run_test("", hdr, rs, &["daft"], &[]);
4682}
4683
4684#[test]
4685fn test_issues_217_222() {
4686 let hdr = indoc! {"
4687 #include <string>
4688 #include <cstdint>
4689 #include <cstddef>
4690
4691 template <typename STRING_TYPE> class BasicStringPiece {
4692 public:
4693 typedef size_t size_type;
4694 typedef typename STRING_TYPE::traits_type traits_type;
4695 typedef typename STRING_TYPE::value_type value_type;
4696 typedef const value_type* pointer;
4697 typedef const value_type& reference;
4698 typedef const value_type& const_reference;
4699 typedef ptrdiff_t difference_type;
4700 typedef const value_type* const_iterator;
4701 typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
4702 static const size_type npos;
4703 };
4704
4705 template<typename CHAR>
4706 class Replacements {
4707 public:
4708 Replacements() {
4709 }
4710 void SetScheme(const CHAR*) {
4711 }
4712 uint16_t a;
4713 };
4714
4715 struct Component {
4716 uint16_t a;
4717 };
4718
4719 template <typename STR>
4720 class StringPieceReplacements : public Replacements<typename STR::value_type> {
4721 private:
4722 using CharT = typename STR::value_type;
4723 using StringPieceT = BasicStringPiece<STR>;
4724 using ParentT = Replacements<CharT>;
4725 using SetterFun = void (ParentT::*)(const CharT*, const Component&);
4726 void SetImpl(SetterFun, StringPieceT) {
4727 }
4728 public:
4729 void SetSchemeStr(const CharT* str) { SetImpl(&ParentT::SetScheme, str); }
4730 };
4731
4732 class GURL {
4733 public:
4734 typedef StringPieceReplacements<std::string> UrlReplacements;
4735 GURL() {}
4736 GURL ReplaceComponents(const Replacements<char>&) const {
4737 return GURL();
4738 }
4739 uint16_t a;
4740 };
4741 "};
4742 let rs = quote! {
4743 ffi::GURL::new().within_unique_ptr();
4744 };
4745 // The block! directives here are to avoid running into
4746 // https://github.com/rust-lang/rust-bindgen/pull/1975
4747 run_test_ex(
4748 "",
4749 hdr,
4750 rs,
4751 quote! { generate!("GURL") block!("StringPiece") block!("Replacements") },
4752 None,
4753 None,
4754 None,
4755 );
4756}
4757
4758#[test]
4759#[ignore] // https://github.com/rust-lang/rust-bindgen/pull/1975, https://github.com/google/autocxx/issues/106
4760fn test_dependent_qualified_type() {
4761 let hdr = indoc! {"
4762 #include <stddef.h>
4763 struct MyString {
4764 typedef char value_type;
4765 };
4766 template<typename T> struct MyStringView {
4767 typedef typename T::value_type view_value_type;
4768 const view_value_type* start;
4769 size_t length;
4770 };
4771 const char* HELLO = \"hello\";
4772 inline MyStringView<MyString> make_string_view() {
4773 MyStringView<MyString> r;
4774 r.start = HELLO;
4775 r.length = 2;
4776 return r;
4777 }
4778 inline size_t take_string_view(const MyStringView<MyString>& bit) {
4779 return bit.length;
4780 }
4781 "};
4782 let rs = quote! {
4783 let sv = ffi::make_string_view();
4784 assert_eq!(ffi::take_string_view(sv.as_ref().unwrap()), 2);
4785 };
4786 run_test("", hdr, rs, &["take_string_view", "make_string_view"], &[]);
4787}
4788
4789#[test]
4790fn test_simple_dependent_qualified_type() {
4791 // bindgen seems to cope with this case just fine
4792 let hdr = indoc! {"
4793 #include <stddef.h>
4794 #include <stdint.h>
4795 struct MyString {
4796 typedef char value_type;
4797 };
4798 template<typename T> struct MyStringView {
4799 typedef typename T::value_type view_value_type;
4800 const view_value_type* start;
4801 size_t length;
4802 };
4803 typedef MyStringView<MyString>::view_value_type MyChar;
4804 inline MyChar make_char() {
4805 return 'a';
4806 }
4807 inline uint32_t take_char(MyChar c) {
4808 return static_cast<unsigned char>(c);
4809 }
4810 "};
4811 let rs = quote! {
4812 let c = ffi::make_char();
4813 assert_eq!(ffi::take_char(c), 97);
4814 };
4815 run_test("", hdr, rs, &["make_char", "take_char"], &[]);
4816}
4817
4818#[test]
4819fn test_ignore_dependent_qualified_type() {
4820 let hdr = indoc! {"
4821 #include <stddef.h>
4822 struct MyString {
4823 typedef char value_type;
4824 };
4825 template<typename T> struct MyStringView {
4826 typedef typename T::value_type view_value_type;
4827 const view_value_type* start;
4828 size_t length;
4829 };
4830 MyStringView<MyString> make_string_view();
4831 struct B {
4832 B() {}
4833 inline size_t take_string_view(const MyStringView<MyString> bit) {
4834 return bit.length;
4835 }
4836 };
4837 "};
4838 let cpp = indoc! {"
4839 const char* HELLO = \"hello\";
4840 MyStringView<MyString> make_string_view() {
4841 MyStringView<MyString> r;
4842 r.start = HELLO;
4843 r.length = 2;
4844 return r;
4845 }
4846 "};
4847 let rs = quote! {
4848 ffi::B::new().within_unique_ptr();
4849 };
4850 run_test(cpp, hdr, rs, &["B"], &[]);
4851}
4852
4853#[test]
4854fn test_ignore_dependent_qualified_type_reference() {
4855 let hdr = indoc! {"
4856 #include <stddef.h>
4857 struct MyString {
4858 typedef char value_type;
4859 };
4860 template<typename T> struct MyStringView {
4861 typedef typename T::value_type view_value_type;
4862 const view_value_type* start;
4863 size_t length;
4864 };
4865 MyStringView<MyString> make_string_view();
4866 struct B {
4867 B() {}
4868 inline size_t take_string_view(const MyStringView<MyString>& bit) {
4869 return bit.length;
4870 }
4871 };
4872 "};
4873 let cpp = indoc! {"
4874 const char* HELLO = \"hello\";
4875 MyStringView<MyString> make_string_view() {
4876 MyStringView<MyString> r;
4877 r.start = HELLO;
4878 r.length = 2;
4879 return r;
4880 }
4881 "};
4882 let rs = quote! {
4883 ffi::B::new().within_unique_ptr();
4884 };
4885 run_test(cpp, hdr, rs, &["B"], &[]);
4886}
4887
4888#[test]
4889fn test_specialization() {
4890 let hdr = indoc! {"
4891 #include <stddef.h>
4892 #include <stdint.h>
4893 #include <string>
4894 #include <type_traits>
4895
4896 template <typename T, bool = std::is_trivially_destructible<T>::value>
4897 struct OptionalStorageBase {
4898 T value_;
4899 };
4900
4901 template <typename T,
4902 bool = std::is_trivially_copy_constructible<T>::value,
4903 bool = std::is_trivially_move_constructible<T>::value>
4904 struct OptionalStorage : OptionalStorageBase<T> {};
4905
4906 template <typename T>
4907 struct OptionalStorage<T,
4908 true /* trivially copy constructible */,
4909 false /* trivially move constructible */>
4910 : OptionalStorageBase<T> {
4911 };
4912
4913 template <typename T>
4914 struct OptionalStorage<T,
4915 false /* trivially copy constructible */,
4916 true /* trivially move constructible */>
4917 : OptionalStorageBase<T> {
4918 };
4919
4920 template <typename T>
4921 struct OptionalStorage<T,
4922 true /* trivially copy constructible */,
4923 true /* trivially move constructible */>
4924 : OptionalStorageBase<T> {
4925 };
4926
4927 template <typename T>
4928 class OptionalBase {
4929 private:
4930 OptionalStorage<T> storage_;
4931 };
4932
4933 template <typename T>
4934 class Optional : public OptionalBase<T> {
4935
4936 };
4937
4938 struct B {
4939 B() {}
4940 void take_optional(Optional<std::string>) {}
4941 uint32_t a;
4942 };
4943 "};
4944 let rs = quote! {
4945 ffi::B::new().within_unique_ptr();
4946 };
4947 run_test("", hdr, rs, &["B"], &[]);
4948}
4949
4950#[test]
4951fn test_private_constructor_make_unique() {
4952 let hdr = indoc! {"
4953 #include <stdint.h>
4954 struct A {
4955 private:
4956 A() {};
4957 public:
4958 uint32_t a;
4959 };
4960 "};
4961 let rs = quote! {};
4962 run_test("", hdr, rs, &["A"], &[]);
4963}
4964
4965#[test]
4966#[ignore] // https://github.com/google/autocxx/issues/266
4967fn test_take_array() {
4968 let hdr = indoc! {"
4969 #include <cstdint>
4970 uint32_t take_array(const uint32_t a[4]) {
4971 return a[0] + a[2];
4972 }
4973 "};
4974 let rs = quote! {
4975 let c: [u32; 4usize] = [ 10, 20, 30, 40 ];
4976 let c = c as *const [_];
4977 assert_eq!(ffi::take_array(&c), 40);
4978 };
4979 run_test("", hdr, rs, &["take_array"], &[]);
4980}
4981
4982#[test]
4983fn test_take_array_in_struct() {
4984 let hdr = indoc! {"
4985 #include <cstdint>
4986 struct data {
4987 char a[4];
4988 };
4989 uint32_t take_array(const data a) {
4990 return a.a[0] + a.a[2];
4991 }
4992 "};
4993 let rs = quote! {
4994 let c = ffi::data { a: [ 10, 20, 30, 40 ] };
4995 assert_eq!(ffi::take_array(c), 40);
4996 };
4997 run_test("", hdr, rs, &["take_array"], &["data"]);
4998}
4999
5000#[test]
5001fn test_union_ignored() {
5002 let hdr = indoc! {"
5003 #include <cstdint>
5004 union A {
5005 uint32_t a;
5006 float b;
5007 };
5008 struct B {
5009 B() :a(1) {}
5010 uint32_t take_union(A) const {
5011 return 3;
5012 }
5013 uint32_t get_a() const { return 2; }
5014 uint32_t a;
5015 };
5016 "};
5017 let rs = quote! {
5018 let b = ffi::B::new().within_unique_ptr();
5019 assert_eq!(b.get_a(), 2);
5020 };
5021 run_test("", hdr, rs, &["B"], &[]);
5022}
5023
5024#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07005025fn test_union_nonpod() {
5026 let hdr = indoc! {"
5027 #include <cstdint>
5028 union A {
5029 uint32_t a;
5030 float b;
5031 };
5032 "};
5033 let rs = quote! {};
5034 run_test("", hdr, rs, &["A"], &[]);
5035}
5036
5037#[test]
5038fn test_union_pod() {
5039 let hdr = indoc! {"
5040 #include <cstdint>
5041 union A {
5042 uint32_t a;
5043 float b;
5044 };
5045 "};
5046 let rs = quote! {};
5047 run_test_expect_fail("", hdr, rs, &[], &["A"]);
5048}
5049
5050#[test]
5051fn test_type_aliased_anonymous_union_ignored() {
5052 let hdr = indoc! {"
5053 #include <cstdint>
5054 namespace test {
5055 typedef union {
5056 int a;
5057 } Union;
5058 };
5059 "};
5060 let rs = quote! {};
5061 run_test("", hdr, rs, &["test::Union"], &[]);
5062}
5063
5064#[test]
5065fn test_type_aliased_anonymous_struct_ignored() {
5066 let hdr = indoc! {"
5067 #include <cstdint>
5068 namespace test {
5069 typedef struct {
5070 int a;
5071 } Struct;
5072 };
5073 "};
5074 let rs = quote! {};
5075 run_test("", hdr, rs, &["test::Struct"], &[]);
5076}
5077
5078#[test]
5079fn test_type_aliased_anonymous_nested_struct_ignored() {
5080 let hdr = indoc! {"
5081 #include <cstdint>
5082 namespace test {
5083 struct Outer {
5084 typedef struct {
5085 int a;
5086 } Struct;
5087 int b;
5088 };
5089 };
5090 "};
5091 let rs = quote! {};
5092 run_test("", hdr, rs, &["test::Outer_Struct"], &[]);
5093}
5094
5095#[ignore] // https://github.com/google/autocxx/issues/1251
5096#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07005097fn test_double_underscores_ignored() {
5098 let hdr = indoc! {"
5099 #include <cstdint>
5100 struct __FOO {
5101 uint32_t a;
5102 };
5103 struct B {
5104 B() :a(1) {}
5105 uint32_t take_foo(__FOO) const {
5106 return 3;
5107 }
5108 void do__something() const { }
5109 uint32_t get_a() const { return 2; }
5110 uint32_t a;
5111 };
5112
5113 struct __default { __default() = default; };
5114 struct __destructor { ~__destructor() = default; };
5115 struct __copy { __copy(const __copy&) = default; };
5116 struct __copy_operator { __copy_operator &operator=(const __copy_operator&) = default; };
5117 struct __move { __move(__move&&) = default; };
5118 struct __move_operator { __move_operator &operator=(const __move_operator&) = default; };
5119 "};
5120 let rs = quote! {
5121 let b = ffi::B::new().within_unique_ptr();
5122 assert_eq!(b.get_a(), 2);
5123 };
5124 run_test(
5125 "",
5126 hdr,
5127 rs,
5128 &[
5129 "B",
5130 "__default",
5131 "__destructor",
5132 "__copy",
5133 "__copy_operator",
5134 "__move",
5135 "__move_operator",
5136 ],
5137 &[],
5138 );
5139}
5140
5141// This test fails on Windows gnu but not on Windows msvc
5142#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
5143#[test]
5144fn test_double_underscore_typedef_ignored() {
5145 let hdr = indoc! {"
5146 #include <cstdint>
5147 typedef int __int32_t;
5148 typedef __int32_t __darwin_pid_t;
5149 typedef __darwin_pid_t pid_t;
5150 struct B {
5151 B() :a(1) {}
5152 uint32_t take_foo(pid_t) const {
5153 return 3;
5154 }
5155 uint32_t get_a() const { return 2; }
5156 uint32_t a;
5157 };
5158 "};
5159 let rs = quote! {
5160 let b = ffi::B::new().within_unique_ptr();
5161 assert_eq!(b.get_a(), 2);
5162 };
5163 run_test("", hdr, rs, &["B"], &[]);
5164}
5165
5166#[test]
5167fn test_double_underscores_fn_namespace() {
5168 let hdr = indoc! {"
5169 namespace __B {
5170 inline void a() {}
5171 };
5172 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07005173 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -07005174}
5175
5176#[test]
5177fn test_typedef_to_ptr_is_marked_unsafe() {
5178 let hdr = indoc! {"
5179 struct _xlocalefoo; /* forward reference */
5180 typedef struct _xlocalefoo * locale_tfoo;
5181 extern \"C\" {
5182 locale_tfoo duplocalefoo(locale_tfoo);
5183 }
5184 "};
5185 let rs = quote! {};
5186 run_test("", hdr, rs, &["duplocalefoo"], &[]);
5187}
5188
5189#[test]
5190fn test_issue_264() {
5191 let hdr = indoc! {"
5192 namespace a {
5193 typedef int b;
5194 //inline namespace c {}
5195 template <typename> class aa;
5196 inline namespace c {
5197 template <typename d, typename = d, typename = aa<d>> class e;
5198 }
5199 typedef e<char> f;
5200 template <typename g, typename, template <typename> typename> struct h {
5201 using i = g;
5202 };
5203 template <typename g, template <typename> class k> using j = h<g, void, k>;
5204 template <typename g, template <typename> class k>
5205 using m = typename j<g, k>::i;
5206 template <typename> struct l { typedef b ab; };
5207 template <typename p> class aa {
5208 public:
5209 typedef p n;
5210 };
5211 struct r {
5212 template <typename p> using o = typename p::c;
5213 };
5214 template <typename ad> struct u : r {
5215 typedef typename ad::n n;
5216 using ae = m<n, o>;
5217 template <typename af, typename> struct v { using i = typename l<f>::ab; };
5218 using ab = typename v<ad, ae>::i;
5219 };
5220 } // namespace a
5221 namespace q {
5222 template <typename ad> struct w : a::u<ad> {};
5223 } // namespace q
5224 namespace a {
5225 inline namespace c {
5226 template <typename, typename, typename ad> class e {
5227 typedef q::w<ad> s;
5228 public:
5229 typedef typename s::ab ab;
5230 };
5231 } // namespace c
5232 } // namespace a
5233 namespace ag {
5234 namespace ah {
5235 typedef a::f::ab t;
5236 class ai {
5237 public:
5238 t aj;
5239 };
5240 class al;
5241 namespace am {
5242 class an {
5243 public:
5244 void ao(ai);
5245 };
5246 } // namespace am
5247 class ap {
5248 public:
5249 al aq();
5250 };
5251 class ar {
5252 public:
5253 am::an as;
5254 };
5255 class al {
5256 public:
5257 ar at;
5258 };
5259 struct au {
5260 ap av;
5261 };
5262 } // namespace ah
5263 } // namespace ag
5264 namespace operations_research {
5265 class aw {
5266 public:
5267 ag::ah::au ax;
5268 };
5269 class Solver {
5270 public:
5271 aw ay;
5272 };
5273 } // namespace operations_research
5274 "};
5275 let rs = quote! {};
5276 run_test_ex(
5277 "",
5278 hdr,
5279 rs,
5280 directives_from_lists(&["operations_research::Solver"], &[], None),
5281 make_cpp17_adder(),
5282 None,
5283 None,
5284 );
5285}
5286
5287#[test]
5288fn test_unexpected_use() {
5289 // https://github.com/google/autocxx/issues/303
5290 let hdr = indoc! {"
5291 typedef int a;
5292 namespace b {
5293 namespace c {
5294 enum d : a;
5295 }
5296 } // namespace b
5297 namespace {
5298 using d = b::c::d;
5299 }
5300 namespace content {
5301 class RenderFrameHost {
5302 public:
5303 RenderFrameHost() {}
5304 d e;
5305 };
5306 } // namespace content
5307 "};
5308 let rs = quote! {
5309 let _ = ffi::content::RenderFrameHost::new().within_unique_ptr();
5310 };
5311 run_test("", hdr, rs, &["content::RenderFrameHost"], &[]);
5312}
5313
5314#[test]
5315fn test_get_pure_virtual() {
5316 let hdr = indoc! {"
5317 #include <cstdint>
5318 class A {
5319 public:
5320 virtual ~A() {}
5321 virtual uint32_t get_val() const = 0;
5322 };
5323 class B : public A {
5324 public:
5325 virtual uint32_t get_val() const { return 3; }
5326 };
5327 const B b;
5328 inline const A* get_a() { return &b; };
5329 "};
5330 let rs = quote! {
5331 let a = ffi::get_a();
5332 let a_ref = unsafe { a.as_ref() }.unwrap();
5333 assert_eq!(a_ref.get_val(), 3);
5334 };
5335 run_test("", hdr, rs, &["A", "get_a"], &[]);
5336}
5337
5338#[test]
5339fn test_abstract_class_no_make_unique() {
5340 // We shouldn't generate a new().within_unique_ptr() for abstract classes.
5341 // The test is successful if the bindings compile, i.e. if autocxx doesn't
5342 // attempt to instantiate the class.
5343 let hdr = indoc! {"
5344 class A {
5345 public:
5346 A() {}
5347 virtual ~A() {}
5348 virtual void foo() const = 0;
5349 };
5350 "};
5351 let rs = quote! {};
5352 run_test("", hdr, rs, &["A"], &[]);
5353}
5354
5355#[test]
5356fn test_derived_abstract_class_no_make_unique() {
5357 let hdr = indoc! {"
5358 class A {
5359 public:
5360 A();
5361 virtual ~A() {}
5362 virtual void foo() const = 0;
5363 };
5364
5365 class B : public A {
5366 public:
5367 B();
5368 };
5369 "};
5370 let rs = quote! {};
5371 run_test("", hdr, rs, &["A", "B"], &[]);
5372}
5373
5374#[test]
5375fn test_recursive_derived_abstract_class_no_make_unique() {
5376 let hdr = indoc! {"
5377 class A {
5378 public:
5379 A() {}
5380 virtual ~A() {}
5381 virtual void foo() const = 0;
5382 };
5383
5384 class B : public A {
5385 public:
5386 B() {};
5387 };
5388
5389 class C : public B {
5390 public:
5391 C() {};
5392 };
5393 "};
5394 let rs = quote! {};
5395 run_test("", hdr, rs, &["A", "B", "C"], &[]);
5396}
5397
5398#[test]
5399fn test_derived_abstract_class_with_no_allowlisting_no_make_unique() {
5400 let hdr = indoc! {"
5401 class A {
5402 public:
5403 A();
5404 virtual ~A() {}
5405 virtual void foo() const = 0;
5406 };
5407
5408 class B : public A {
5409 public:
5410 B();
5411 };
5412 "};
5413 let rs = quote! {};
5414 run_test("", hdr, rs, &["B"], &[]);
5415}
5416
5417#[test]
5418fn test_vector_of_pointers() {
5419 // Just ensures the troublesome API is ignored
5420 let hdr = indoc! {"
5421 #include <vector>
5422 namespace operations_research {
5423 class a;
5424 class Solver {
5425 public:
5426 struct b c(std::vector<a *>);
5427 };
5428 class a {};
5429 } // namespace operations_research
5430 "};
5431 let rs = quote! {};
5432 run_test("", hdr, rs, &["operations_research::Solver"], &[]);
5433}
5434
5435#[test]
5436fn test_vec_and_up_of_primitives() {
5437 let hdr = indoc! {"
5438 #include <vector>
5439 #include <memory>
5440 #include <cstdint>
5441 class Value {
5442 public:
5443 Value(std::vector<uint32_t>) {} // OK
5444 Value(std::unique_ptr<uint32_t>) {} // should be ignored
5445 Value(std::vector<int>) {} // should be ignored
5446 Value(std::unique_ptr<int>) {} // should be ignored
5447 Value(std::vector<char>) {} // should be ignored
5448 Value(std::unique_ptr<char>) {} // should be ignored
5449 Value(std::vector<float>) {} // OK
5450 Value(std::unique_ptr<float>) {} // should be ignored
5451 Value(std::vector<bool>) {} // should be ignored
5452 Value(std::unique_ptr<bool>) {} // should be ignored
5453 Value(std::vector<size_t>) {} // OK
5454 Value(std::unique_ptr<size_t>) {} // should be ignored
5455 };
5456 inline std::vector<uint32_t> make_vec_uint32_t() {
5457 std::vector<uint32_t> a;
5458 return a;
5459 }
5460 inline std::vector<float> make_vec_float() {
5461 std::vector<float> a;
5462 return a;
5463 }
5464 inline std::vector<size_t> make_vec_size_t() {
5465 std::vector<size_t> a;
5466 return a;
5467 }
5468 "};
5469 let rs = quote! {
5470 ffi::Value::new(ffi::make_vec_uint32_t()).within_box();
5471 ffi::Value::new6(ffi::make_vec_float()).within_box();
5472 ffi::Value::new10(ffi::make_vec_size_t()).within_box();
5473 };
5474 run_test(
5475 "",
5476 hdr,
5477 rs,
5478 &[
5479 "Value",
5480 "make_vec_uint32_t",
5481 "make_vec_float",
5482 "make_vec_size_t",
5483 ],
5484 &[],
5485 );
5486}
5487
5488#[test]
5489fn test_pointer_to_pointer() {
5490 // Just ensures the troublesome API is ignored
5491 let hdr = indoc! {"
5492 namespace operations_research {
5493 class a;
5494 class Solver {
5495 public:
5496 struct b c(a **);
5497 };
5498 class a {};
5499 } // namespace operations_research
5500 "};
5501 let rs = quote! {};
5502 run_test("", hdr, rs, &["operations_research::Solver"], &[]);
5503}
5504
5505#[test]
5506fn test_defines_effective() {
5507 let hdr = indoc! {"
5508 #include <cstdint>
5509 #ifdef FOO
5510 inline uint32_t a() { return 4; }
5511 #endif
5512 "};
5513 let rs = quote! {
5514 ffi::a();
5515 };
5516 run_test_ex(
5517 "",
5518 hdr,
5519 rs,
5520 quote! { generate!("a") },
5521 make_clang_arg_adder(&["-DFOO"]),
5522 None,
5523 None,
5524 );
5525}
5526
5527#[test]
5528#[ignore] // https://github.com/google/autocxx/issues/227
5529fn test_function_pointer_template() {
5530 let hdr = indoc! {"
5531 typedef int a;
5532 namespace std {
5533 template <typename> class b;
5534 }
5535 typedef a c;
5536 namespace operations_research {
5537 class d;
5538 class Solver {
5539 public:
5540 typedef std::b<c()> IndexEvaluator3;
5541 d e(IndexEvaluator3);
5542 };
5543 class d {};
5544 } // namespace operations_research
5545 "};
5546 let rs = quote! {};
5547 run_test("", hdr, rs, &["operations_research::Solver"], &[]);
5548}
5549
5550#[test]
5551fn test_cvoid() {
5552 let hdr = indoc! {"
5553 #include <memory>
5554 #include <cstdint>
5555 inline void* a() {
5556 return static_cast<void*>(new int(3));
5557 }
5558 inline uint32_t b(void* p) {
5559 int* p_int = static_cast<int*>(p);
5560 auto val = *p_int;
5561 delete p_int;
5562 return val;
5563 }
5564 "};
5565 let rs = quote! {
5566 let ptr = ffi::a();
5567 let res = unsafe { ffi::b(ptr) };
5568 assert_eq!(res, 3);
5569 };
5570 run_test("", hdr, rs, &["a", "b"], &[]);
5571}
5572
5573#[test]
5574fn test_c_schar() {
5575 let hdr = indoc! {"
5576 inline signed char a() {
5577 return 8;
5578 }
5579 "};
5580 let rs = quote! {
5581 assert_eq!(ffi::a(), 8);
5582 };
5583 run_test("", hdr, rs, &["a"], &[]);
5584}
5585
5586#[test]
5587fn test_c_uchar() {
5588 let hdr = indoc! {"
5589 inline unsigned char a() {
5590 return 8;
5591 }
5592 "};
5593 let rs = quote! {
5594 assert_eq!(ffi::a(), 8);
5595 };
5596 run_test("", hdr, rs, &["a"], &[]);
5597}
5598
5599#[test]
5600fn test_c_ulonglong() {
5601 // We don't test all the different variable-length integer types which we populate.
5602 // If one works, they probably all do. Hopefully.
5603 let hdr = indoc! {"
5604 inline unsigned long long a() {
5605 return 8;
5606 }
5607 "};
5608 let rs = quote! {
5609 assert_eq!(ffi::a(), autocxx::c_ulonglong(8));
5610 };
5611 run_test("", hdr, rs, &["a"], &[]);
5612}
5613
5614#[test]
5615fn test_string_transparent_function() {
5616 let hdr = indoc! {"
5617 #include <string>
5618 #include <cstdint>
5619 inline uint32_t take_string(std::string a) { return a.size(); }
5620 "};
5621 let rs = quote! {
5622 assert_eq!(ffi::take_string("hello"), 5);
5623 };
5624 run_test("", hdr, rs, &["take_string"], &[]);
5625}
5626
5627#[test]
5628fn test_string_transparent_method() {
5629 let hdr = indoc! {"
5630 #include <string>
5631 #include <cstdint>
5632 struct A {
5633 A() {}
5634 inline uint32_t take_string(std::string a) const { return a.size(); }
5635 };
5636 "};
5637 let rs = quote! {
5638 let a = ffi::A::new().within_unique_ptr();
5639 assert_eq!(a.take_string("hello"), 5);
5640 };
5641 run_test("", hdr, rs, &["A"], &[]);
5642}
5643
5644#[test]
5645fn test_string_transparent_static_method() {
5646 let hdr = indoc! {"
5647 #include <string>
5648 #include <cstdint>
5649 struct A {
5650 A() {}
5651 static inline uint32_t take_string(std::string a) { return a.size(); }
5652 };
5653 "};
5654 let rs = quote! {
5655 assert_eq!(ffi::A::take_string("hello"), 5);
5656 };
5657 run_test("", hdr, rs, &["A"], &[]);
5658}
5659
5660#[test]
5661#[ignore] // https://github.com/google/autocxx/issues/490
5662fn test_issue_490() {
5663 let hdr = indoc! {"
5664 typedef int a;
5665 typedef long unsigned size_t;
5666 namespace std {
5667 namespace {
5668 using ::size_t;
5669 template <class b, b c> struct g { static const b value = c; };
5670 template <bool d> using e = g<bool, d>;
5671 typedef e<true> true_type;
5672 template <size_t, size_t> struct ag {};
5673 template <class b> typename b ::h move();
5674 template <class> class allocator;
5675 template <class> class vector;
5676 } // namespace
5677 } // namespace std
5678 void *operator new(size_t, void *);
5679 namespace std {
5680 namespace {
5681 template <class> struct iterator;
5682 template <class b, class> struct ay { using h = b *; };
5683 template <class b> struct bj { b bk; };
5684 template <class bm, class> class bn : bj<bm> {};
5685 template <class b, class i = b> class unique_ptr {
5686 typedef i bp;
5687 typedef typename ay<b, bp>::h bh;
5688 bn<bh, bp> bq;
5689
5690 public:
5691 unique_ptr();
5692 unique_ptr(bh);
5693 bh get() const;
5694 bh release();
5695 };
5696 template <class = void> struct bt;
5697 } // namespace
5698 } // namespace std
5699 typedef a bv;
5700 namespace absl {
5701 template <typename ce> class cj {
5702 public:
5703 using bh = ce *;
5704 using iterator = bh;
5705 };
5706 namespace j {
5707 template <class ce> struct cp {
5708 using k = ce;
5709 using cq = std::bt<>;
5710 };
5711 template <class ce> using cr = typename cp<ce>::k;
5712 template <class ce> using cs = typename cp<ce>::cq;
5713 template <class, class, class, class> class ct {
5714 public:
5715 class iterator {};
5716 class cu {
5717 cu(iterator);
5718 iterator cv;
5719 };
5720 };
5721 template <typename> struct cw;
5722 } // namespace j
5723 template <class ce, class k = j::cr<ce>, class cq = j::cs<ce>,
5724 class cx = std::allocator<ce>>
5725 class cy : public j::ct<j::cw<ce>, k, cq, cx> {};
5726 } // namespace absl
5727 namespace cz {
5728 template <typename da> class db { std::ag<sizeof(a), alignof(da)> c; };
5729 } // namespace cz
5730 namespace spanner {
5731 class l;
5732 class ColumnList {
5733 public:
5734 typedef absl::cj<l>::iterator iterator;
5735 iterator begin();
5736 };
5737 class dd {
5738 union {
5739 cz::db<absl::cy<bv>::cu> e;
5740 };
5741 };
5742 class Row {
5743 public:
5744 bool f(dd);
5745 };
5746 } // namespace spanner
5747 "};
5748 let rs = quote! {};
5749 run_test("", hdr, rs, &["spanner::Row", "spanner::ColumnList"], &[]);
5750}
5751
5752#[test]
5753fn test_immovable_object() {
5754 let hdr = indoc! {"
5755 class A {
5756 public:
5757 A();
5758 A(A&&) = delete;
5759 };
5760
5761 class B{
5762 public:
5763 B();
5764 B(const B&) = delete;
5765 };
5766 "};
5767 let rs = quote! {};
5768 run_test("", hdr, rs, &["A", "B"], &[]);
5769}
5770
5771#[test]
5772fn test_struct_with_reference() {
5773 let hdr = indoc! {"
5774 #include <cstdint>
5775 #include <utility>
5776 struct A {
5777 uint32_t a;
5778 };
5779 struct B {
5780 B(const A& param) : a(param) {}
5781 const A& a;
5782 };
5783 "};
5784 let rs = quote! {};
5785 run_test("", hdr, rs, &["A", "B"], &[]);
5786}
5787
5788#[test]
5789fn test_struct_with_rvalue() {
5790 let hdr = indoc! {"
5791 #include <cstdint>
5792 #include <utility>
5793 struct A {
5794 uint32_t a;
5795 };
5796 struct B {
5797 B(A&& param) : a(std::move(param)) {}
5798 A&& a;
5799 };
5800 "};
5801 let rs = quote! {};
5802 run_test("", hdr, rs, &["A", "B"], &[]);
5803}
5804
5805#[test]
5806fn test_immovable_nested_object() {
5807 let hdr = indoc! {"
5808 struct C {
5809 class A {
5810 public:
5811 A();
5812 A(A&&) = delete;
5813 };
5814
5815 class B{
5816 public:
5817 B();
5818 B(const B&) = delete;
5819 };
5820 };
5821 "};
5822 let rs = quote! {};
5823 run_test("", hdr, rs, &["C_A", "C_B"], &[]);
5824}
5825
5826#[test]
5827fn test_type_called_type() {
5828 let hdr = indoc! {"
5829 namespace a {
5830 template<int _Len>
5831 struct b
5832 {
5833 union type
5834 {
5835 unsigned char __data[_Len];
5836 struct foo {
5837 int a;
5838 };
5839 };
5840 };
5841 }
5842 inline void take_type(a::b<4>::type) {}
5843 "};
5844 let rs = quote! {};
5845 run_test("", hdr, rs, &["take_type"], &[]);
5846}
5847
5848#[test]
5849fn test_bridge_conflict_ty() {
5850 let hdr = indoc! {"
5851 namespace a {
5852 struct Key { int a; };
5853 }
5854 namespace b {
5855 struct Key { int a; };
5856 }
5857 "};
5858 let rs = quote! {};
5859 run_test("", hdr, rs, &["a::Key", "b::Key"], &[]);
5860}
5861
5862#[test]
5863fn test_bridge_conflict_ty_fn() {
5864 let hdr = indoc! {"
5865 namespace a {
5866 struct Key { int a; };
5867 }
5868 namespace b {
5869 inline void Key() {}
5870 }
5871 "};
5872 let rs = quote! {};
5873 run_test("", hdr, rs, &["a::Key", "b::Key"], &[]);
5874}
5875
5876#[test]
5877fn test_issue_506() {
5878 let hdr = indoc! {"
5879 namespace std {
5880 template <class, class> class am;
5881 typedef am<char, char> an;
5882 } // namespace std
5883 namespace be {
5884 class bf {
5885 virtual std::an bg() = 0;
5886 };
5887 class bh : bf {};
5888 } // namespace be
5889 namespace spanner {
5890 class Database;
5891 class Row {
5892 public:
5893 Row(be::bh *);
5894 };
5895 } // namespace spanner
5896 "};
5897 let rs = quote! {};
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07005898 run_test_ex(
5899 "",
5900 hdr,
5901 rs,
5902 directives_from_lists(&["spanner::Database", "spanner::Row"], &[], None),
5903 // This is normally a valid warning for generating bindings for this code, but we're doing
5904 // it on purpose as a regression test on minimized code so we'll just ignore it.
5905 make_clang_optional_arg_adder(&[], &["-Wno-delete-abstract-non-virtual-dtor"]),
5906 None,
5907 None,
5908 );
Brian Silverman4e662aa2022-05-11 23:10:19 -07005909}
5910
5911#[test]
5912fn test_private_inheritance() {
5913 let hdr = indoc! {"
5914 class A {
5915 public:
5916 void foo() {}
5917 int a;
5918 };
5919 class B : A {
5920 public:
5921 void bar() {}
5922 int b;
5923 };
5924 "};
5925 let rs = quote! {};
5926 run_test("", hdr, rs, &["A", "B"], &[]);
5927}
5928
5929#[test]
5930fn test_error_generated_for_static_data() {
5931 let hdr = indoc! {"
5932 #include <cstdint>
5933 struct A {
5934 A() {}
5935 uint32_t a;
5936 };
5937 static A FOO = A();
5938 "};
5939 let rs = quote! {};
5940 run_test_ex(
5941 "",
5942 hdr,
5943 rs,
5944 quote! { generate!("FOO")},
5945 None,
5946 Some(make_error_finder("FOO")),
5947 None,
5948 );
5949}
5950
5951#[test]
5952fn test_error_generated_for_array_dependent_function() {
5953 let hdr = indoc! {"
5954 #include <cstdint>
5955 #include <functional>
5956 inline void take_func(std::function<bool(const uint32_t number)>) {
5957 }
5958 "};
5959 let rs = quote! {};
5960 run_test_ex(
5961 "",
5962 hdr,
5963 rs,
5964 quote! { generate! ("take_func")},
5965 None,
5966 Some(make_error_finder("take_func")),
5967 None,
5968 );
5969}
5970
5971#[test]
5972#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
5973#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
5974fn test_error_generated_for_array_dependent_method() {
5975 let hdr = indoc! {"
5976 #include <cstdint>
5977 #include <functional>
5978 struct A {
5979 void take_func(std::function<bool(const uint32_t number)>) {
5980 }
5981 };
5982 "};
5983 let rs = quote! {};
5984 run_test_ex(
5985 "",
5986 hdr,
5987 rs,
5988 quote! { generate! ("A")},
5989 None,
5990 Some(make_string_finder(
5991 ["take_func", "couldn't be generated"]
5992 .map(|s| s.to_string())
5993 .to_vec(),
5994 )),
5995 None,
5996 );
5997}
5998
5999#[test]
6000fn test_error_generated_for_pod_with_nontrivial_destructor() {
6001 // take_a is necessary here because cxx won't generate the required
6002 // static assertions unless the type is actually used in some context
6003 // where cxx needs to decide it's trivial or non-trivial.
6004 let hdr = indoc! {"
6005 #include <cstdint>
6006 #include <functional>
6007 struct A {
6008 ~A() {}
6009 };
6010 inline void take_a(A) {}
6011 "};
6012 let rs = quote! {};
6013 run_test_expect_fail("", hdr, rs, &["take_a"], &["A"]);
6014}
6015
6016#[test]
6017fn test_error_generated_for_pod_with_nontrivial_move_constructor() {
6018 // take_a is necessary here because cxx won't generate the required
6019 // static assertions unless the type is actually used in some context
6020 // where cxx needs to decide it's trivial or non-trivial.
6021 let hdr = indoc! {"
6022 #include <cstdint>
6023 #include <functional>
6024 struct A {
6025 A() = default;
6026 A(A&&) {}
6027 };
6028 inline void take_a(A) {}
6029 "};
6030 let rs = quote! {};
6031 run_test_expect_fail("", hdr, rs, &["take_a"], &["A"]);
6032}
6033
6034#[test]
6035fn test_double_destruction() {
6036 let hdr = indoc! {"
6037 #include <stdio.h>
6038 #include <stdlib.h>
6039 // A simple type to let Rust verify the destructor is run.
6040 struct NotTriviallyDestructible {
6041 NotTriviallyDestructible() = default;
6042 NotTriviallyDestructible(const NotTriviallyDestructible&) = default;
6043 NotTriviallyDestructible(NotTriviallyDestructible&&) = default;
6044
6045 ~NotTriviallyDestructible() {}
6046 };
6047
6048 struct ExplicitlyDefaulted {
6049 ExplicitlyDefaulted() = default;
6050 ~ExplicitlyDefaulted() = default;
6051
6052 NotTriviallyDestructible flag;
6053 };
6054 "};
6055 let rs = quote! {
6056 moveit! {
6057 let mut moveit_t = ffi::ExplicitlyDefaulted::new();
6058 }
6059 };
6060 match do_run_test(
6061 "",
6062 hdr,
6063 rs,
6064 directives_from_lists(
6065 &[],
6066 &["NotTriviallyDestructible", "ExplicitlyDefaulted"],
6067 None,
6068 ),
6069 None,
6070 None,
6071 None,
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07006072 "unsafe_ffi",
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07006073 None,
Brian Silverman4e662aa2022-05-11 23:10:19 -07006074 ) {
6075 Err(TestError::CppBuild(_)) => {} // be sure this fails due to a static_assert
6076 // rather than some runtime problem
6077 _ => panic!("Test didn't fail as expected"),
6078 };
6079}
6080
6081#[test]
6082fn test_keyword_function() {
6083 let hdr = indoc! {"
6084 inline void move(int) {};
6085 "};
6086 let rs = quote! {};
6087 run_test("", hdr, rs, &["move_"], &[]);
6088}
6089
6090#[test]
6091fn test_keyword_method() {
6092 let hdr = indoc! {"
6093 struct A {
6094 int a;
6095 inline void move() {};
6096 };
6097 "};
6098 let rs = quote! {};
6099 run_test("", hdr, rs, &["A"], &[]);
6100}
6101
6102#[test]
6103fn test_doc_passthru() {
6104 let hdr = indoc! {"
6105 #include <cstdint>
6106 /// Elephants!
6107 struct A {
6108 uint32_t a;
6109 };
6110 /// Giraffes!
6111 struct B {
6112 uint32_t a;
6113 };
6114 /// Rhinos!
6115 inline uint32_t get_a() { return 3; }
6116 "};
6117 let rs = quote! {};
6118 run_test_ex(
6119 "",
6120 hdr,
6121 rs,
6122 directives_from_lists(&["A", "get_a"], &["B"], None),
6123 None,
6124 Some(make_string_finder(
6125 ["Giraffes", "Elephants", "Rhinos"]
6126 .map(|s| s.to_string())
6127 .to_vec(),
6128 )),
6129 None,
6130 );
6131}
6132
6133#[test]
6134fn test_closure() {
6135 // Ensuring presence of this closure doesn't break other things
6136 let hdr = indoc! {"
6137 #include <functional>
6138 #include <cstdint>
6139
6140 inline bool take_closure(std::function<bool(const uint32_t number)> fn) {
6141 return fn(5);
6142 }
6143 inline uint32_t get_a() {
6144 return 3;
6145 }
6146 "};
6147 let rs = quote! {
6148 assert_eq!(ffi::get_a(), 3);
6149 };
6150 run_test("", hdr, rs, &["get_a"], &[]);
6151}
6152
6153#[test]
6154fn test_multiply_nested_inner_type() {
6155 let hdr = indoc! {"
6156 struct Turkey {
6157 struct Duck {
6158 struct Hen {
6159 int wings;
6160 };
6161 struct HenWithDefault {
6162 HenWithDefault() = default;
6163 int wings;
6164 };
6165 struct HenWithDestructor {
6166 ~HenWithDestructor() = default;
6167 int wings;
6168 };
6169 struct HenWithCopy {
6170 HenWithCopy() = default;
6171 HenWithCopy(const HenWithCopy&) = default;
6172 int wings;
6173 };
6174 struct HenWithMove {
6175 HenWithMove() = default;
6176 HenWithMove(HenWithMove&&) = default;
6177 int wings;
6178 };
6179 };
6180 };
6181 "};
6182 let rs = quote! {
6183 ffi::Turkey_Duck_Hen::new().within_unique_ptr();
6184 ffi::Turkey_Duck_HenWithDefault::new().within_unique_ptr();
6185 ffi::Turkey_Duck_HenWithDestructor::new().within_unique_ptr();
6186 ffi::Turkey_Duck_HenWithCopy::new().within_unique_ptr();
6187 ffi::Turkey_Duck_HenWithMove::new().within_unique_ptr();
6188
6189 moveit! {
6190 let hen = ffi::Turkey_Duck_Hen::new();
6191 let moved_hen = autocxx::moveit::new::mov(hen);
6192 let _copied_hen = autocxx::moveit::new::copy(moved_hen);
6193
6194 let hen = ffi::Turkey_Duck_HenWithDefault::new();
6195 let moved_hen = autocxx::moveit::new::mov(hen);
6196 let _copied_hen = autocxx::moveit::new::copy(moved_hen);
6197
6198 let _hen = ffi::Turkey_Duck_HenWithDestructor::new();
6199
6200 let hen = ffi::Turkey_Duck_HenWithCopy::new();
6201 let _copied_hen = autocxx::moveit::new::copy(hen);
6202
6203 let hen = ffi::Turkey_Duck_HenWithMove::new();
6204 let _moved_hen = autocxx::moveit::new::mov(hen);
6205 }
6206 };
6207 run_test(
6208 "",
6209 hdr,
6210 rs,
6211 &[],
6212 &[
6213 "Turkey_Duck_Hen",
6214 "Turkey_Duck_HenWithDefault",
6215 "Turkey_Duck_HenWithDestructor",
6216 "Turkey_Duck_HenWithCopy",
6217 "Turkey_Duck_HenWithMove",
6218 ],
6219 );
6220}
6221
6222#[test]
6223fn test_underscored_namespace_for_inner_type() {
6224 let hdr = indoc! {"
6225 namespace __foo {
6226 struct daft {
6227 struct bob {
6228 int a;
6229 };
6230 int a;
6231 };
6232 }
6233 inline void bar(__foo::daft::bob) {}
6234 "};
6235 let rs = quote! {};
6236 run_test("", hdr, rs, &["bar"], &[]);
6237}
6238
6239#[test]
6240fn test_blocklist_not_overly_broad() {
6241 // This is a regression test. We used to block anything that starts with "rust" or "std",
6242 // not just items in the "rust" and "std" namespaces. We therefore test that functions starting
6243 // with "rust" or "std" get imported.
6244 let hdr = indoc! {"
6245 inline void rust_func() { }
6246 inline void std_func() { }
6247 "};
6248 let rs = quote! {
6249 ffi::rust_func();
6250 ffi::std_func();
6251 };
6252 run_test("", hdr, rs, &["rust_func", "std_func"], &[]);
6253}
6254
6255#[test]
6256#[ignore] // https://github.com/google/autocxx/issues/837
6257fn test_ref_qualified_method() {
6258 let hdr = indoc! {"
6259 struct A {
6260 void foo() & {}
6261 };
6262 "};
6263 let rs = quote! {
6264 A::new().within_unique_ptr().foo();
6265 };
6266 run_test("", hdr, rs, &["A"], &[]);
6267}
6268
6269#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
6270#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
6271#[test]
6272fn test_stringview() {
6273 // Test that APIs using std::string_view do not otherwise cause errors.
6274 let hdr = indoc! {"
6275 #include <string_view>
6276 #include <string>
6277 void take_string_view(std::string_view) {}
6278 std::string_view return_string_view(const std::string& a) { return std::string_view(a); }
6279 "};
6280 let rs = quote! {};
6281 run_test_ex(
6282 "",
6283 hdr,
6284 rs,
6285 directives_from_lists(&["take_string_view", "return_string_view"], &[], None),
6286 make_cpp17_adder(),
6287 None,
6288 None,
6289 );
6290}
6291
6292#[test]
6293fn test_include_cpp_alone() {
6294 let hdr = indoc! {"
6295 #include <cstdint>
6296 inline uint32_t give_int() {
6297 return 5;
6298 }
6299 "};
6300 let hexathorpe = Token![#](Span::call_site());
6301 let rs = quote! {
6302 use autocxx::include_cpp;
6303 include_cpp! {
6304 #hexathorpe include "input.h"
6305 safety!(unsafe_ffi)
6306 generate!("give_int")
6307 }
6308 fn main() {
6309 assert_eq!(ffi::give_int(), 5);
6310 }
6311 };
6312 do_run_test_manual("", hdr, rs, None, None).unwrap();
6313}
6314
6315#[test]
6316fn test_include_cpp_in_path() {
6317 let hdr = indoc! {"
6318 #include <cstdint>
6319 inline uint32_t give_int() {
6320 return 5;
6321 }
6322 "};
6323 let hexathorpe = Token![#](Span::call_site());
6324 let rs = quote! {
6325 autocxx::include_cpp! {
6326 #hexathorpe include "input.h"
6327 safety!(unsafe_ffi)
6328 generate!("give_int")
6329 }
6330 fn main() {
6331 assert_eq!(ffi::give_int(), 5);
6332 }
6333 };
6334 do_run_test_manual("", hdr, rs, None, None).unwrap();
6335}
6336
6337#[test]
6338fn test_bitset() {
6339 let hdr = indoc! {"
6340 #include <cstddef>
6341 template <size_t _N_words, size_t _Size>
6342 class __bitset
6343 {
6344 public:
6345 typedef size_t __storage_type;
6346 __storage_type __first_[_N_words];
6347 inline bool all() {
6348 return false;
6349 }
6350 };
6351
6352 template <size_t _Size>
6353 class bitset
6354 : private __bitset<_Size == 0 ? 0 : (_Size - 1) / (sizeof(size_t) * 8) + 1, _Size>
6355 {
6356 public:
6357 static const unsigned __n_words = _Size == 0 ? 0 : (_Size - 1) / (sizeof(size_t) * 8) + 1;
6358 typedef __bitset<__n_words, _Size> base;
6359 bool all() const noexcept;
6360 };
6361
6362
6363 typedef bitset<1> mybitset;
6364 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07006365 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -07006366}
6367
6368#[test]
6369fn test_cint_vector() {
6370 let hdr = indoc! {"
6371 #include <vector>
6372 #include <cstdint>
6373 inline std::vector<int32_t> give_vec() {
6374 return std::vector<int32_t> {1,2};
6375 }
6376 "};
6377
6378 let rs = quote! {
6379 assert_eq!(ffi::give_vec().as_ref().unwrap().as_slice(), &[1,2]);
6380 };
6381
6382 run_test("", hdr, rs, &["give_vec"], &[]);
6383}
6384
6385#[test]
6386#[ignore] // https://github.com/google/autocxx/issues/422
6387fn test_int_vector() {
6388 let hdr = indoc! {"
6389 #include <vector>
6390 std::vector<int> give_vec() {
6391 return std::vector<int> {1,2};
6392 }
6393 "};
6394
6395 let rs = quote! {
6396 assert_eq!(ffi::give_vec().as_ref().unwrap().as_slice(), &[autocxx::c_int(1),autocxx::c_int(2)]);
6397 };
6398
6399 run_test("", hdr, rs, &["give_vec"], &[]);
6400}
6401
6402#[test]
6403fn test_size_t() {
6404 let hdr = indoc! {"
6405 #include <cstddef>
6406 inline size_t get_count() { return 7; }
6407 "};
6408
6409 let rs = quote! {
6410 ffi::get_count();
6411 };
6412
6413 run_test_ex(
6414 "",
6415 hdr,
6416 rs,
6417 directives_from_lists(&["get_count"], &[], None),
6418 None,
6419 Some(make_rust_code_finder(vec![
6420 quote! {fn get_count() -> usize},
6421 ])),
6422 None,
6423 );
6424}
6425
6426#[test]
6427fn test_deleted_function() {
6428 // We shouldn't generate bindings for deleted functions.
6429 // The test is successful if the bindings compile, i.e. if autocxx doesn't
6430 // attempt to call the deleted function.
6431 let hdr = indoc! {"
6432 class A {
6433 public:
6434 void foo() = delete;
6435 };
6436 "};
6437 let rs = quote! {};
6438 run_test("", hdr, rs, &["A"], &[]);
6439}
6440
6441#[test]
6442fn test_ignore_move_constructor() {
6443 let hdr = indoc! {"
6444 class A {
6445 public:
6446 A() {}
6447 A(A&&) {};
6448 };
6449 "};
6450 let rs = quote! {};
6451 run_test("", hdr, rs, &["A"], &[]);
6452}
6453
6454#[test]
6455fn test_ignore_function_with_rvalue_ref() {
6456 let hdr = indoc! {"
6457 #include <string>
6458
6459 void moveme(std::string &&);
6460 "};
6461 let rs = quote! {};
6462 run_test("", hdr, rs, &["moveme"], &[]);
6463}
6464
6465#[test]
6466fn test_take_nonpod_rvalue_from_up() {
6467 let hdr = indoc! {"
6468 #include <string>
6469 struct A {
6470 std::string a;
6471 };
6472 inline void take_a(A&&) {};
6473 "};
6474 let rs = quote! {
6475 let a = ffi::A::new().within_unique_ptr();
6476 ffi::take_a(a);
6477
6478 let a2 = ffi::A::new().within_box();
6479 ffi::take_a(a2);
6480 };
6481 run_test("", hdr, rs, &["A", "take_a"], &[]);
6482}
6483
6484#[test]
6485fn test_take_nonpod_rvalue_from_stack() {
6486 let hdr = indoc! {"
6487 #include <string>
6488 struct A {
6489 std::string a;
6490 };
6491 inline void take_a(A&&) {};
6492 "};
6493 let rs = quote! {
6494 moveit! { let a = ffi::A::new() };
6495 ffi::take_a(a);
6496 };
6497 run_test("", hdr, rs, &["A", "take_a"], &[]);
6498}
6499
6500#[test]
6501fn test_overloaded_ignored_function() {
6502 // When overloaded functions are ignored during import, the placeholder
6503 // functions generated for them should have unique names, just as they
6504 // would have if they had been imported successfully.
6505 // The test is successful if the bindings compile.
6506 let hdr = indoc! {"
6507 struct Blocked {};
6508 class A {
6509 public:
6510 void take_blocked(Blocked);
6511 void take_blocked(Blocked, int);
6512 };
6513 "};
6514 let rs = quote! {};
6515 run_test_ex(
6516 "",
6517 hdr,
6518 rs,
6519 quote! {
6520 generate!("A")
6521 block!("Blocked")
6522 },
6523 None,
6524 None,
6525 None,
6526 );
6527}
6528
6529#[test]
6530fn test_namespaced_constant() {
6531 let hdr = indoc! {"
6532 namespace A {
6533 const int kConstant = 3;
6534 }
6535 "};
6536 let rs = quote! {
6537 assert_eq!(ffi::A::kConstant, 3);
6538 };
6539 run_test("", hdr, rs, &["A::kConstant"], &[]);
6540}
6541
6542#[test]
6543fn test_issue_470_492() {
6544 let hdr = indoc! {"
6545 namespace std {
6546 template <bool, typename _Iftrue, typename _Iffalse> struct a;
6547 }
6548 template <typename> struct b;
6549 template <typename d> struct c {
6550 typedef std::a<b<d>::c, int, int> e;
6551 };
6552 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07006553 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -07006554}
6555
6556#[test]
6557fn test_no_impl() {
6558 let hdr = indoc! {"
6559 struct A {
6560 int a;
6561 };
6562 "};
6563 let rs = quote! {};
6564 run_test_ex(
6565 "",
6566 hdr,
6567 rs,
6568 quote! {
6569 exclude_impls!()
6570 exclude_utilities!()
6571 generate!("A")
6572 },
6573 None,
6574 None,
6575 None,
6576 );
6577}
6578
6579#[test]
6580fn test_generate_all() {
6581 let hdr = indoc! {"
6582 #include <cstdint>
6583 inline uint32_t give_int() {
6584 return 5;
6585 }
6586 "};
6587 let rs = quote! {
6588 assert_eq!(ffi::give_int(), 5);
6589 };
6590 run_test_ex(
6591 "",
6592 hdr,
6593 rs,
6594 quote! {
6595 generate_all!()
6596 },
6597 None,
6598 None,
6599 None,
6600 );
6601}
6602
6603#[test]
6604fn test_std_thing() {
6605 let hdr = indoc! {"
6606 #include <cstdint>
6607 namespace std {
6608 struct A {
6609 uint8_t a;
6610 };
6611 }
6612 typedef char daft;
6613 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07006614 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -07006615}
6616
6617#[test]
6618fn test_two_mods() {
6619 let hdr = indoc! {"
6620 #include <cstdint>
6621 struct A {
6622 uint32_t a;
6623 };
6624 inline A give_a() {
6625 A a;
6626 a.a = 5;
6627 return a;
6628 }
6629 inline uint32_t get_a(A a) {
6630 return a.a;
6631 }
6632 struct B {
6633 uint32_t a;
6634 };
6635 inline B give_b() {
6636 B a;
6637 a.a = 8;
6638 return a;
6639 }
6640 inline uint32_t get_b(B a) {
6641 return a.a;
6642 }
6643 "};
6644 let hexathorpe = Token![#](Span::call_site());
6645 let rs = quote! {
6646 use autocxx::prelude::*;
6647 include_cpp! {
6648 #hexathorpe include "input.h"
6649 safety!(unsafe_ffi)
6650 generate!("give_a")
6651 generate!("get_a")
6652 }
6653 include_cpp! {
6654 #hexathorpe include "input.h"
6655 name!(ffi2)
6656 generate!("give_b")
6657 generate!("get_b")
6658 }
6659 fn main() {
6660 let a = ffi::give_a().within_unique_ptr();
6661 assert_eq!(ffi::get_a(a), 5);
6662 let b = unsafe { ffi2::give_b().within_unique_ptr() };
6663 assert_eq!(unsafe { ffi2::get_b(b) }, 8);
6664 }
6665 };
6666 do_run_test_manual("", hdr, rs, None, None).unwrap();
6667}
6668
6669#[test]
6670fn test_manual_bridge() {
6671 let hdr = indoc! {"
6672 #include <cstdint>
6673 inline uint32_t give_int() {
6674 return 5;
6675 }
6676 inline uint32_t give_int2() {
6677 return 5;
6678 }
6679 "};
6680 let hexathorpe = Token![#](Span::call_site());
6681 let rs = quote! {
6682 autocxx::include_cpp! {
6683 #hexathorpe include "input.h"
6684 safety!(unsafe_ffi)
6685 generate!("give_int")
6686 }
6687 #[cxx::bridge]
6688 mod ffi2 {
6689 unsafe extern "C++" {
6690 include!("input.h");
6691 fn give_int2() -> u32;
6692 }
6693 }
6694 fn main() {
6695 assert_eq!(ffi::give_int(), 5);
6696 assert_eq!(ffi2::give_int2(), 5);
6697 }
6698 };
6699 do_run_test_manual("", hdr, rs, None, None).unwrap();
6700}
6701
6702#[test]
6703fn test_manual_bridge_mixed_types() {
6704 let hdr = indoc! {"
6705 #include <memory>
6706 struct A {
6707 int a;
6708 };
6709 inline int take_A(const A& a) {
6710 return a.a;
6711 }
6712 inline std::unique_ptr<A> give_A() {
6713 auto a = std::make_unique<A>();
6714 a->a = 5;
6715 return a;
6716 }
6717 "};
6718 let hexathorpe = Token![#](Span::call_site());
6719 let rs = quote! {
6720 use autocxx::prelude::*;
6721 autocxx::include_cpp! {
6722 #hexathorpe include "input.h"
6723 safety!(unsafe_ffi)
6724 generate!("take_A")
6725 generate!("A")
6726 }
6727 #[cxx::bridge]
6728 mod ffi2 {
6729 unsafe extern "C++" {
6730 include!("input.h");
6731 type A = crate::ffi::A;
6732 fn give_A() -> UniquePtr<A>;
6733 }
6734 }
6735 fn main() {
6736 let a = ffi2::give_A();
6737 assert_eq!(ffi::take_A(&a), autocxx::c_int(5));
6738 }
6739 };
6740 do_run_test_manual("", hdr, rs, None, None).unwrap();
6741}
6742
6743#[test]
6744fn test_extern_cpp_type_cxx_bridge() {
6745 let hdr = indoc! {"
6746 #include <cstdint>
6747 struct A {
6748 A() : a(0) {}
6749 int a;
6750 };
6751 inline void handle_a(const A&) {
6752 }
6753 inline A create_a() {
6754 A a;
6755 return a;
6756 }
6757 "};
6758 let hexathorpe = Token![#](Span::call_site());
6759 let rs = quote! {
6760 use autocxx::prelude::*;
6761 include_cpp! {
6762 #hexathorpe include "input.h"
6763 safety!(unsafe_ffi)
6764 generate!("handle_a")
6765 generate!("create_a")
6766 extern_cpp_opaque_type!("A", crate::ffi2::A)
6767 }
6768 #[cxx::bridge]
6769 pub mod ffi2 {
6770 unsafe extern "C++" {
6771 include!("input.h");
6772 type A;
6773 }
6774 impl UniquePtr<A> {}
6775 }
6776 fn main() {
6777 let a = ffi::create_a();
6778 ffi::handle_a(&a);
6779 }
6780 };
6781 do_run_test_manual("", hdr, rs, None, None).unwrap();
6782}
6783
6784#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07006785fn test_extern_cpp_type_different_name() {
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::DifferentA)
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 pub use ffi2::A as DifferentA;
6818 fn main() {
6819 let a = ffi::create_a();
6820 ffi::handle_a(&a);
6821 }
6822 };
6823 do_run_test_manual("", hdr, rs, None, None).unwrap();
6824}
6825
6826#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07006827fn test_extern_cpp_type_two_include_cpp() {
6828 let hdr = indoc! {"
6829 #include <cstdint>
6830 struct A {
6831 A() : a(0) {}
6832 int a;
6833 };
6834 enum B {
6835 VARIANT,
6836 };
6837 inline void handle_a(const A&) {
6838 }
6839 inline A create_a(B) {
6840 A a;
6841 return a;
6842 }
6843 "};
6844 let hexathorpe = Token![#](Span::call_site());
6845 let rs = quote! {
6846 pub mod base {
6847 autocxx::include_cpp! {
6848 #hexathorpe include "input.h"
6849 name!(ffi2)
6850 safety!(unsafe_ffi)
6851 generate!("A")
6852 generate!("B")
6853 }
6854 pub use ffi2::*;
6855 }
6856 pub mod dependent {
6857 autocxx::include_cpp! {
6858 #hexathorpe include "input.h"
6859 safety!(unsafe_ffi)
6860 generate!("handle_a")
6861 generate!("create_a")
6862 extern_cpp_type!("A", crate::base::A)
6863 extern_cpp_type!("B", super::super::base::B)
6864 pod!("B")
6865 }
6866 pub use ffi::*;
6867 }
6868 fn main() {
6869 use autocxx::prelude::*;
6870 let a = dependent::create_a(base::B::VARIANT).within_box();
6871 dependent::handle_a(&a);
6872 }
6873 };
6874 do_run_test_manual("", hdr, rs, None, None).unwrap();
6875}
6876
6877#[test]
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07006878/// Tests extern_cpp_type with a type inside a namespace.
6879fn test_extern_cpp_type_namespace() {
6880 let hdr = indoc! {"
6881 #include <cstdint>
6882 namespace b {
6883 struct B {
6884 B() {}
6885 };
6886 } // namespace b
6887 struct A {
6888 A() {}
6889 b::B make_b() { return b::B(); }
6890 };
6891 "};
6892 let hexathorpe = Token![#](Span::call_site());
6893 let rs = quote! {
6894 pub mod b {
6895 autocxx::include_cpp! {
6896 #hexathorpe include "input.h"
6897 safety!(unsafe_ffi)
6898 name!(ffi_b)
6899 generate_pod!("b::B")
6900 }
6901 pub use ffi_b::b::B;
6902 }
6903 pub mod a {
6904 autocxx::include_cpp! {
6905 #hexathorpe include "input.h"
6906 safety!(unsafe_ffi)
6907 name!(ffi_a)
6908 generate_pod!("A")
6909 extern_cpp_type!("b::B", crate::b::B)
6910 }
6911 pub use ffi_a::A;
6912 }
6913 fn main() {
6914 use autocxx::prelude::*;
6915 let _ = crate::a::A::new().within_unique_ptr().as_mut().unwrap().make_b();
6916 }
6917 };
6918 do_run_test_manual("", hdr, rs, None, None).unwrap();
6919}
6920
6921#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07006922#[ignore] // because we currently require UniquePtrTarget which this can't implement
6923fn test_extern_cpp_type_manual() {
6924 let hdr = indoc! {"
6925 #include <cstdint>
6926 struct A {
6927 int a;
6928 };
6929 inline void handle_a(const A& a) {
6930 }
6931 inline A create_a() {
6932 A a;
6933 return a;
6934 }
6935 "};
6936 let hexathorpe = Token![#](Span::call_site());
6937 let rs = quote! {
6938 autocxx::include_cpp! {
6939 #hexathorpe include "input.h"
6940 safety!(unsafe_ffi)
6941 generate!("handle_a")
6942 generate!("create_a")
6943 extern_cpp_type!("A", crate::ffi2::A)
6944 }
6945 pub mod ffi2 {
6946 use autocxx::cxx::{type_id, ExternType};
6947 #[repr(C)]
6948 pub struct A {
6949 a: std::os::raw::c_int
6950 }
6951 unsafe impl ExternType for A {
6952 type Kind = autocxx::cxx::kind::Opaque;
6953 type Id = type_id!("A");
6954 }
6955
6956 }
6957 fn main() {
6958 let a = ffi2::A { a: 3 };
6959 ffi::handle_a(&a);
6960 }
6961 };
6962 do_run_test_manual("", hdr, rs, None, None).unwrap();
6963}
6964
6965#[test]
6966fn test_issue486() {
6967 let hdr = indoc! {"
6968 namespace a {
6969 namespace spanner {
6970 class Key;
6971 }
6972 } // namespace a
6973 namespace spanner {
6974 class Key {
6975 public:
6976 bool b(a::spanner::Key &);
6977 };
6978 } // namespace spanner
6979 "};
6980 let rs = quote! {};
6981 run_test("", hdr, rs, &["spanner::Key"], &[]);
6982}
6983
6984#[test]
6985#[ignore]
6986fn test_issue616() {
6987 let hdr = indoc! {"
6988 namespace N {
6989 template <typename> class B{};
6990 template <typename c> class C {
6991 public:
6992 using U = B<c>;
6993 };
6994 }
6995 class A : N::C<A> {
6996 U u;
6997 };
6998 "};
6999 let rs = quote! {};
7000 run_test("", hdr, rs, &["A"], &[]);
7001}
7002
7003#[test]
7004fn test_shared_ptr() {
7005 let hdr = indoc! {"
7006 #include <memory>
7007 struct A {
7008 int a;
7009 };
7010 inline std::shared_ptr<A> make_shared_int() {
7011 return std::make_shared<A>(A { 3 });
7012 }
7013 inline int take_shared_int(std::shared_ptr<A> a) {
7014 return a->a;
7015 }
7016 inline std::weak_ptr<A> shared_to_weak(std::shared_ptr<A> a) {
7017 return std::weak_ptr<A>(a);
7018 }
7019 "};
7020 let rs = quote! {
7021 let a = ffi::make_shared_int();
7022 assert_eq!(ffi::take_shared_int(a.clone()), autocxx::c_int(3));
7023 ffi::shared_to_weak(a).upgrade();
7024 };
7025 run_test(
7026 "",
7027 hdr,
7028 rs,
7029 &["make_shared_int", "take_shared_int", "shared_to_weak"],
7030 &[],
7031 );
7032}
7033
7034#[test]
7035#[ignore] // https://github.com/google/autocxx/issues/799
7036fn test_shared_ptr_const() {
7037 let hdr = indoc! {"
7038 #include <memory>
7039 inline std::shared_ptr<const int> make_shared_int() {
7040 return std::make_shared<const int>(3);
7041 }
7042 inline int take_shared_int(std::shared_ptr<const int> a) {
7043 return *a;
7044 }
7045 "};
7046 let rs = quote! {
7047 let a = ffi::make_shared_int();
7048 assert_eq!(ffi::take_shared_int(a.clone()), autocxx::c_int(3));
7049 };
7050 run_test("", hdr, rs, &["make_shared_int", "take_shared_int"], &[]);
7051}
7052
7053#[test]
7054fn test_rust_reference() {
7055 let hdr = indoc! {"
7056 #include <cstdint>
7057
7058 struct RustType;
7059 inline uint32_t take_rust_reference(const RustType&) {
7060 return 4;
7061 }
7062 "};
7063 let rs = quote! {
7064 let foo = RustType(3);
7065 assert_eq!(ffi::take_rust_reference(&foo), 4);
7066 };
7067 run_test_ex(
7068 "",
7069 hdr,
7070 rs,
7071 quote! {
7072 generate!("take_rust_reference")
7073 extern_rust_type!(RustType)
7074 },
7075 None,
7076 None,
7077 Some(quote! {
7078 pub struct RustType(i32);
7079 }),
7080 );
7081}
7082
7083#[test]
7084fn test_rust_reference_autodiscover() {
7085 let hdr = indoc! {"
7086 #include <cstdint>
7087
7088 struct RustType;
7089 inline uint32_t take_rust_reference(const RustType&) {
7090 return 4;
7091 }
7092 "};
7093 let rs = quote! {
7094 let foo = RustType(3);
7095 let result = ffi::take_rust_reference(&foo);
7096 assert_eq!(result, 4);
7097 };
7098 run_test_ex(
7099 "",
7100 hdr,
7101 rs,
7102 quote! {},
7103 Some(Box::new(EnableAutodiscover)),
7104 None,
7105 Some(quote! {
7106 #[autocxx::extern_rust::extern_rust_type]
7107 pub struct RustType(i32);
7108 }),
7109 );
7110}
7111
7112#[test]
7113fn test_pass_thru_rust_reference() {
7114 let hdr = indoc! {"
7115 #include <cstdint>
7116
7117 struct RustType;
7118 inline const RustType& pass_rust_reference(const RustType& a) {
7119 return a;
7120 }
7121 "};
7122 let rs = quote! {
7123 let foo = RustType(3);
7124 assert_eq!(ffi::pass_rust_reference(&foo).0, 3);
7125 };
7126 run_test_ex(
7127 "",
7128 hdr,
7129 rs,
7130 quote! {
7131 generate!("pass_rust_reference")
7132 extern_rust_type!(RustType)
7133 },
7134 None,
7135 None,
7136 Some(quote! {
7137 pub struct RustType(i32);
7138 }),
7139 );
7140}
7141
7142#[test]
7143fn test_extern_rust_method() {
7144 let hdr = indoc! {"
7145 #include <cstdint>
7146 struct RustType;
7147 uint32_t examine(const RustType& foo);
7148 "};
7149 let cxx = indoc! {"
7150 uint32_t examine(const RustType& foo) {
7151 return foo.get();
7152 }"};
7153 let rs = quote! {
7154 let a = RustType(74);
7155 assert_eq!(ffi::examine(&a), 74);
7156 };
7157 run_test_ex(
7158 cxx,
7159 hdr,
7160 rs,
7161 directives_from_lists(&["examine"], &[], None),
7162 Some(Box::new(EnableAutodiscover)),
7163 None,
7164 Some(quote! {
7165 #[autocxx::extern_rust::extern_rust_type]
7166 pub struct RustType(i32);
7167 impl RustType {
7168 #[autocxx::extern_rust::extern_rust_function]
7169 pub fn get(&self) -> i32 {
7170 return self.0
7171 }
7172 }
7173 }),
7174 );
7175}
7176
7177#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007178fn test_extern_rust_fn_callback() {
7179 let hdr = indoc! {"
7180 struct a {};
7181 "};
7182 let hexathorpe = Token![#](Span::call_site());
7183 let rs = quote! {
7184 autocxx::include_cpp! {
7185 #hexathorpe include "input.h"
7186 safety!(unsafe_ffi)
7187 generate!("a")
7188 }
7189
7190 use ffi::a;
7191 use std::pin::Pin;
7192
7193 #[autocxx::extern_rust::extern_rust_function]
7194 pub fn called_from_cpp(_a: Pin<&mut a>) {}
7195
7196 fn main() {}
7197 };
7198 do_run_test_manual("", hdr, rs, None, None).unwrap();
7199}
7200
7201// TODO: there are various other tests for extern_rust_fn we should add:
7202// 1) taking mutable and immutable references
7203// 2) ensuring that types on which the signature depends as receiver,
7204// parameters and return are not garbage collected
7205
7206#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07007207fn test_rust_reference_no_autodiscover() {
7208 let hdr = indoc! {"
7209 #include <cstdint>
7210
7211 struct RustType;
7212 inline uint32_t take_rust_reference(const RustType&) {
7213 return 4;
7214 }
7215 "};
7216 let rs = quote! {
7217 let foo = RustType(3);
7218 let result = ffi::take_rust_reference(&foo);
7219 assert_eq!(result, 4);
7220 };
7221 run_test_ex(
7222 "",
7223 hdr,
7224 rs,
7225 directives_from_lists(&["take_rust_reference"], &[], None),
7226 None,
7227 None,
7228 Some(quote! {
7229 #[autocxx::extern_rust::extern_rust_type]
7230 pub struct RustType(i32);
7231 }),
7232 );
7233}
7234
7235#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007236fn test_rust_box() {
7237 let hdr = indoc! {"
7238 #include <cstdint>
7239 #include <cxx.h>
7240
7241 struct RustType;
7242 inline uint32_t take_rust_box(rust::Box<RustType>) {
7243 return 4;
7244 }
7245 "};
7246 let rs = quote! {
7247 let foo = Box::new(RustType(3));
7248 let result = ffi::take_rust_box(foo);
7249 assert_eq!(result, 4);
7250 };
7251 run_test_ex(
7252 "",
7253 hdr,
7254 rs,
7255 directives_from_lists(&["take_rust_box"], &[], None),
7256 None,
7257 None,
7258 Some(quote! {
7259 #[autocxx::extern_rust::extern_rust_type]
7260 pub struct RustType(i32);
7261 }),
7262 );
7263}
7264
7265#[test]
7266fn test_rust_reference_no_autodiscover_no_usage() {
7267 let rs = quote! {
7268 let _ = RustType(3);
7269 };
7270 run_test_ex(
7271 "",
7272 "",
7273 rs,
7274 directives_from_lists(&[], &[], None),
7275 None,
7276 None,
7277 Some(quote! {
7278 #[autocxx::extern_rust::extern_rust_type]
7279 pub struct RustType(i32);
7280 }),
7281 );
7282}
7283
7284#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07007285#[cfg_attr(skip_windows_msvc_failing_tests, ignore)]
7286// TODO - replace make_clang_arg_adder with something that knows how to add an MSVC-suitable
7287// directive for the cc build.
7288fn test_cpp17() {
7289 let hdr = indoc! {"
7290 static_assert(__cplusplus >= 201703L, \"This file expects a C++17 compatible compiler.\");
7291 inline void foo() {}
7292 "};
7293 run_test_ex(
7294 "",
7295 hdr,
7296 quote! {
7297 ffi::foo();
7298 },
7299 quote! {
7300 generate!("foo")
7301 },
7302 make_cpp17_adder(),
7303 None,
7304 None,
7305 );
7306}
7307
7308#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007309fn test_box_extern_rust_type() {
Brian Silverman4e662aa2022-05-11 23:10:19 -07007310 let hdr = indoc! {"
7311 #include <cxx.h>
7312 struct Foo;
7313 inline void take_box(rust::Box<Foo>) {
7314 }
7315 "};
7316 run_test_ex(
7317 "",
7318 hdr,
7319 quote! {
7320 ffi::take_box(Box::new(Foo { a: "Hello".into() }))
7321 },
7322 quote! {
7323 generate!("take_box")
7324 extern_rust_type!(Foo)
7325 },
7326 None,
7327 None,
7328 Some(quote! {
7329 pub struct Foo {
7330 a: String,
7331 }
7332 }),
7333 );
7334}
7335
7336#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007337fn test_box_return_placement_new() {
7338 let hdr = indoc! {"
7339 #include <cxx.h>
7340 struct Foo;
7341 struct Foo2;
7342 struct Ret {};
7343 inline Ret take_box(rust::Box<Foo>, rust::Box<Foo2>) {
7344 return Ret{};
7345 }
7346 "};
7347 run_test_ex(
7348 "",
7349 hdr,
7350 quote! {
7351 let _ = ffi::take_box(
7352 Box::new(Foo { a: "Hello".into() }),
7353 Box::new(bar::Foo2 { a: "Goodbye".into() })
7354 );
7355 },
7356 quote! {
7357 generate!("take_box")
7358 extern_rust_type!(Foo)
7359 generate!("Ret")
7360 },
7361 None,
7362 None,
7363 Some(quote! {
7364 pub struct Foo {
7365 a: String,
7366 }
7367 mod bar {
7368 #[autocxx::extern_rust::extern_rust_type]
7369 pub struct Foo2 {
7370 pub a: String,
7371 }
7372 }
7373 }),
7374 );
7375}
7376
7377#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07007378fn test_box_via_extern_rust() {
7379 let hdr = indoc! {"
7380 #include <cxx.h>
7381 struct Foo;
7382 inline void take_box(rust::Box<Foo>) {
7383 }
7384 "};
7385 run_test_ex(
7386 "",
7387 hdr,
7388 quote! {
7389 ffi::take_box(Box::new(Foo { a: "Hello".into() }))
7390 },
7391 quote! {},
7392 Some(Box::new(EnableAutodiscover)),
7393 None,
7394 Some(quote! {
7395 #[autocxx::extern_rust::extern_rust_type]
7396 pub struct Foo {
7397 a: String,
7398 }
7399 }),
7400 );
7401}
7402
7403#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007404fn test_box_via_extern_rust_no_include_cpp() {
7405 let hdr = indoc! {"
7406 #include <cxx.h>
7407 struct Foo;
7408 inline void take_box(rust::Box<Foo>) {
7409 }
7410 "};
7411 do_run_test_manual(
7412 "",
7413 hdr,
7414 quote! {
7415 #[autocxx::extern_rust::extern_rust_type]
7416 pub struct Foo {
7417 a: String,
7418 }
7419
7420 fn main() {
7421 }
7422 },
7423 Some(Box::new(EnableAutodiscover)),
7424 None,
7425 )
7426 .unwrap();
7427}
7428
7429#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07007430fn test_box_via_extern_rust_in_mod() {
7431 let hdr = indoc! {"
7432 #include <cxx.h>
7433 struct Foo;
7434 inline void take_box(rust::Box<Foo>) {
7435 }
7436 "};
7437 run_test_ex(
7438 "",
7439 hdr,
7440 quote! {
7441 ffi::take_box(Box::new(bar::Foo { a: "Hello".into() }))
7442 },
7443 quote! {},
7444 Some(Box::new(EnableAutodiscover)),
7445 None,
7446 Some(quote! {
7447 mod bar {
7448 #[autocxx::extern_rust::extern_rust_type]
7449 pub struct Foo {
7450 pub a: String,
7451 }
7452 }
7453 }),
7454 );
7455}
7456
7457#[test]
7458fn test_extern_rust_fn_simple() {
7459 let cpp = indoc! {"
7460 void foo() {
7461 my_rust_fun();
7462 }
7463 "};
7464 let hdr = indoc! {"
7465 #include <cxx.h>
7466 inline void do_thing() {}
7467 "};
7468 run_test_ex(
7469 cpp,
7470 hdr,
7471 quote! {
7472 ffi::do_thing();
7473 },
7474 quote! {
7475 generate!("do_thing")
7476 },
7477 Some(Box::new(EnableAutodiscover)),
7478 None,
7479 Some(quote! {
7480 #[autocxx::extern_rust::extern_rust_function]
7481 fn my_rust_fun() {
7482 }
7483 }),
7484 );
7485}
7486
7487#[test]
7488fn test_extern_rust_fn_in_mod() {
7489 let hdr = indoc! {"
7490 #include <cxx.h>
7491 inline void do_thing() {}
7492 "};
7493 run_test_ex(
7494 "",
7495 hdr,
7496 quote! {},
7497 quote! {
7498 generate!("do_thing")
7499 },
7500 Some(Box::new(EnableAutodiscover)),
7501 None,
7502 Some(quote! {
7503 mod bar {
7504 #[autocxx::extern_rust::extern_rust_function]
7505 pub fn my_rust_fun() {
7506
7507 }
7508 }
7509 }),
7510 );
7511}
7512
7513#[test]
7514fn test_issue_956() {
7515 let hdr = indoc! {"
7516 #include <cstdint>
7517 inline void take_int(int&) {}
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007518 inline void take_uint16(uint16_t) {}
7519 inline void take_us(unsigned short) {}
7520 inline void take_char16(char16_t) {}
7521 inline void take_uint16_ref(uint16_t&) {}
7522 inline void take_char16_ref(char16_t &) {}
Brian Silverman4e662aa2022-05-11 23:10:19 -07007523 "};
7524 run_test(
7525 "",
7526 hdr,
7527 quote! {},
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07007528 &[
7529 "take_int",
7530 "take_uint16",
7531 "take_char16",
7532 "take_uint16_ref",
7533 "take_char16_ref",
7534 "take_us",
7535 ],
Brian Silverman4e662aa2022-05-11 23:10:19 -07007536 &[],
7537 );
7538}
7539
7540#[test]
7541fn test_extern_rust_fn_no_autodiscover() {
7542 let hdr = indoc! {"
7543 #include <cxx.h>
7544 "};
7545 let cpp = indoc! {"
7546 void call_it() {
7547 my_rust_fun();
7548 }
7549 "};
7550 run_test_ex(
7551 cpp,
7552 hdr,
7553 quote! {},
7554 quote! {},
7555 None,
7556 None,
7557 Some(quote! {
7558 mod bar {
7559 #[autocxx::extern_rust::extern_rust_function]
7560 pub fn my_rust_fun() {
7561
7562 }
7563 }
7564 }),
7565 );
7566}
7567
7568#[test]
7569fn test_pv_subclass_mut() {
7570 let hdr = indoc! {"
7571 #include <cstdint>
7572
7573 class Observer {
7574 public:
7575 Observer() {}
7576 virtual void foo() = 0;
7577 virtual ~Observer() {}
7578 };
7579 inline void bar() {}
7580 "};
7581 run_test_ex(
7582 "",
7583 hdr,
7584 quote! {
7585 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7586 },
7587 quote! {
7588 generate!("bar")
7589 subclass!("Observer",MyObserver)
7590 },
7591 None,
7592 None,
7593 Some(quote! {
7594 use autocxx::subclass::CppSubclass;
7595 use ffi::Observer_methods;
7596 #[autocxx::subclass::subclass]
7597 pub struct MyObserver {
7598 a: u32
7599 }
7600 impl Observer_methods for MyObserver {
7601 fn foo(&mut self) {
7602 }
7603 }
7604 }),
7605 );
7606}
7607
7608#[test]
7609fn test_pv_subclass_const() {
7610 let hdr = indoc! {"
7611 #include <cstdint>
7612
7613 class Observer {
7614 public:
7615 Observer() {}
7616 virtual void foo() const = 0;
7617 virtual ~Observer() {}
7618 };
7619 inline void bar() {}
7620 "};
7621 run_test_ex(
7622 "",
7623 hdr,
7624 quote! {
7625 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7626 },
7627 quote! {
7628 generate!("bar")
7629 subclass!("Observer",MyObserver)
7630 },
7631 None,
7632 None,
7633 Some(quote! {
7634 use autocxx::subclass::CppSubclass;
7635 use ffi::Observer_methods;
7636 #[autocxx::subclass::subclass]
7637 pub struct MyObserver {
7638 a: u32
7639 }
7640 impl Observer_methods for MyObserver {
7641 fn foo(&self) {
7642 }
7643 }
7644 }),
7645 );
7646}
7647
7648#[test]
7649fn test_pv_subclass_calls_impossible() {
7650 let hdr = indoc! {"
7651 #include <cstdint>
7652
7653 class Observer {
7654 public:
7655 Observer() {}
7656 virtual void foo() const = 0;
7657 virtual ~Observer() {}
7658 };
7659 inline void bar() {}
7660 "};
7661 run_test_expect_fail_ex(
7662 "",
7663 hdr,
7664 quote! {
7665 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7666 },
7667 quote! {
7668 generate!("bar")
7669 subclass!("Observer",MyObserver)
7670 },
7671 None,
7672 None,
7673 Some(quote! {
7674 use autocxx::subclass::CppSubclass;
7675 use ffi::Observer_methods;
7676 #[autocxx::subclass::subclass]
7677 pub struct MyObserver {
7678 a: u32
7679 }
7680 impl Observer_methods for MyObserver {
7681 fn foo(&self) {
7682 use ffi::Observer_supers;
7683 self.foo_super()
7684 }
7685 }
7686 }),
7687 );
7688}
7689
7690#[test]
7691fn test_pv_subclass_not_pub() {
7692 let hdr = indoc! {"
7693 #include <cstdint>
7694
7695 class Observer {
7696 public:
7697 Observer() {}
7698 virtual void foo() const = 0;
7699 virtual ~Observer() {}
7700 };
7701 inline void bar() {}
7702 "};
7703 run_test_expect_fail_ex(
7704 "",
7705 hdr,
7706 quote! {
7707 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7708 },
7709 quote! {
7710 generate!("bar")
7711 subclass!("Observer",MyObserver)
7712 },
7713 None,
7714 None,
7715 Some(quote! {
7716 use autocxx::subclass::CppSubclass;
7717 use ffi::Observer_methods;
7718 #[autocxx::subclass::subclass]
7719 struct MyObserver {
7720 a: u32
7721 }
7722 impl Observer_methods for MyObserver {
7723 fn foo(&self) {
7724 }
7725 }
7726 }),
7727 );
7728}
7729
7730#[test]
7731fn test_pv_subclass_ptr_param() {
7732 let hdr = indoc! {"
7733 #include <cstdint>
7734 struct A {
7735 uint8_t a;
7736 };
7737
7738 class Observer {
7739 public:
7740 Observer() {}
7741 virtual void foo(const A*) const {};
7742 virtual ~Observer() {}
7743 };
7744 "};
7745 run_test_ex(
7746 "",
7747 hdr,
7748 quote! {
7749 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7750 },
7751 quote! {
7752 generate!("A")
7753 subclass!("Observer",MyObserver)
7754 },
7755 None,
7756 None,
7757 Some(quote! {
7758 use autocxx::subclass::CppSubclass;
7759 use ffi::Observer_methods;
7760 #[autocxx::subclass::subclass]
7761 pub struct MyObserver {
7762 a: u32
7763 }
7764 impl Observer_methods for MyObserver {
7765 unsafe fn foo(&self, a: *const ffi::A) {
7766 use ffi::Observer_supers;
7767 self.foo_super(a)
7768 }
7769 }
7770 }),
7771 );
7772}
7773
7774#[test]
7775fn test_pv_subclass_return() {
7776 let hdr = indoc! {"
7777 #include <cstdint>
7778
7779 class Observer {
7780 public:
7781 Observer() {}
7782 virtual uint32_t foo() const = 0;
7783 virtual ~Observer() {}
7784 };
7785 inline void bar() {}
7786 "};
7787 run_test_ex(
7788 "",
7789 hdr,
7790 quote! {
7791 MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7792 },
7793 quote! {
7794 generate!("bar")
7795 subclass!("Observer",MyObserver)
7796 },
7797 None,
7798 None,
7799 Some(quote! {
7800 use autocxx::subclass::CppSubclass;
7801 use ffi::Observer_methods;
7802 #[autocxx::subclass::subclass]
7803 pub struct MyObserver {
7804 a: u32
7805 }
7806 impl Observer_methods for MyObserver {
7807 fn foo(&self) -> u32 {
7808 4
7809 }
7810 }
7811 }),
7812 );
7813}
7814
7815#[test]
7816fn test_pv_subclass_passed_to_fn() {
7817 let hdr = indoc! {"
7818 #include <cstdint>
7819
7820 class Observer {
7821 public:
7822 Observer() {}
7823 virtual uint32_t foo() const = 0;
7824 virtual ~Observer() {}
7825 };
7826 inline void take_observer(const Observer&) {}
7827 "};
7828 run_test_ex(
7829 "",
7830 hdr,
7831 quote! {
7832 let o = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7833 ffi::take_observer(o.borrow().as_ref());
7834 },
7835 quote! {
7836 generate!("take_observer")
7837 subclass!("Observer",MyObserver)
7838 },
7839 None,
7840 None,
7841 Some(quote! {
7842 use autocxx::subclass::CppSubclass;
7843 use ffi::Observer_methods;
7844 #[autocxx::subclass::subclass]
7845 pub struct MyObserver {
7846 a: u32
7847 }
7848 impl Observer_methods for MyObserver {
7849 fn foo(&self) -> u32 {
7850 4
7851 }
7852 }
7853 }),
7854 );
7855}
7856
7857#[test]
7858fn test_pv_subclass_derive_defaults() {
7859 let hdr = indoc! {"
7860 #include <cstdint>
7861
7862 class Observer {
7863 public:
7864 Observer() {}
7865 virtual uint32_t foo() const = 0;
7866 virtual ~Observer() {}
7867 };
7868 inline void take_observer(const Observer&) {}
7869 "};
7870 run_test_ex(
7871 "",
7872 hdr,
7873 quote! {
7874 use autocxx::subclass::CppSubclassDefault;
7875 let o = MyObserver::default_rust_owned();
7876 ffi::take_observer(o.borrow().as_ref());
7877 },
7878 quote! {
7879 generate!("take_observer")
7880 subclass!("Observer",MyObserver)
7881 },
7882 None,
7883 None,
7884 Some(quote! {
7885 #[autocxx::subclass::subclass]
7886 #[derive(Default)]
7887 pub struct MyObserver {
7888 a: u32
7889 }
7890 impl ffi::Observer_methods for MyObserver {
7891 fn foo(&self) -> u32 {
7892 4
7893 }
7894 }
7895 }),
7896 );
7897}
7898
7899#[test]
7900fn test_non_pv_subclass_simple() {
7901 let hdr = indoc! {"
7902 #include <cstdint>
7903
7904 class Observer {
7905 public:
7906 Observer() {}
7907 virtual void foo() const {}
7908 virtual ~Observer() {}
7909 };
7910 inline void bar() {}
7911 "};
7912 run_test_ex(
7913 "",
7914 hdr,
7915 quote! {
7916 let obs = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7917 obs.borrow().foo();
7918 },
7919 quote! {
7920 generate!("bar")
7921 subclass!("Observer",MyObserver)
7922 },
7923 None,
7924 None,
7925 Some(quote! {
7926 use autocxx::subclass::CppSubclass;
7927 use ffi::Observer_methods;
7928 #[autocxx::subclass::subclass]
7929 pub struct MyObserver {
7930 a: u32
7931 }
7932 impl Observer_methods for MyObserver {
7933 }
7934 }),
7935 );
7936}
7937
7938#[test]
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07007939/// Tests the Rust code generated for subclasses when there's a `std` module in scope representing
7940/// the C++ `std` namespace. This breaks if any of the generated Rust code fails to fully qualify
7941/// its references to the Rust `std`.
7942fn test_subclass_with_std() {
7943 let hdr = indoc! {"
7944 #include <cstdint>
7945 #include <chrono>
7946
7947 class Observer {
7948 public:
7949 Observer() {}
7950 virtual void foo() const {}
7951 virtual ~Observer() {}
7952
7953 void unused(std::chrono::nanoseconds) {}
7954 };
7955 "};
7956 run_test_ex(
7957 "",
7958 hdr,
7959 quote! {
7960 let obs = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
7961 obs.borrow().foo();
7962 },
7963 quote! {
7964 subclass!("Observer",MyObserver)
7965 },
7966 None,
7967 None,
7968 Some(quote! {
7969 use autocxx::subclass::CppSubclass;
7970 use ffi::Observer_methods;
7971 #[autocxx::subclass::subclass]
7972 pub struct MyObserver {
7973 a: u32
7974 }
7975 impl Observer_methods for MyObserver {
7976 }
7977 }),
7978 );
7979}
7980
7981#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07007982fn test_two_subclasses() {
7983 let hdr = indoc! {"
7984 #include <cstdint>
7985
7986 class Observer {
7987 public:
7988 Observer() {}
7989 virtual void foo() const {}
7990 virtual ~Observer() {}
7991 };
7992 inline void bar() {}
7993 "};
7994 run_test_ex(
7995 "",
7996 hdr,
7997 quote! {
7998 let obs = MyObserverA::new_rust_owned(MyObserverA { a: 3, cpp_peer: Default::default() });
7999 obs.borrow().foo();
8000 let obs = MyObserverB::new_rust_owned(MyObserverB { a: 3, cpp_peer: Default::default() });
8001 obs.borrow().foo();
8002 },
8003 quote! {
8004 generate!("bar")
8005 subclass!("Observer",MyObserverA)
8006 subclass!("Observer",MyObserverB)
8007 },
8008 None,
8009 None,
8010 Some(quote! {
8011 use autocxx::subclass::CppSubclass;
8012 use ffi::Observer_methods;
8013 #[autocxx::subclass::subclass]
8014 pub struct MyObserverA {
8015 a: u32
8016 }
8017 impl Observer_methods for MyObserverA {
8018 }
8019 #[autocxx::subclass::subclass]
8020 pub struct MyObserverB {
8021 a: u32
8022 }
8023 impl Observer_methods for MyObserverB {
8024 }
8025 }),
8026 );
8027}
8028
8029#[test]
8030fn test_two_superclasses_with_same_name_method() {
8031 let hdr = indoc! {"
8032 #include <cstdint>
8033
8034 class ObserverA {
8035 public:
8036 ObserverA() {}
8037 virtual void foo() const {}
8038 virtual ~ObserverA() {}
8039 };
8040
8041 class ObserverB {
8042 public:
8043 ObserverB() {}
8044 virtual void foo() const {}
8045 virtual ~ObserverB() {}
8046 };
8047 inline void bar() {}
8048 "};
8049 run_test_ex(
8050 "",
8051 hdr,
8052 quote! {
8053 let obs = MyObserverA::new_rust_owned(MyObserverA { a: 3, cpp_peer: Default::default() });
8054 obs.borrow().foo();
8055 let obs = MyObserverB::new_rust_owned(MyObserverB { a: 3, cpp_peer: Default::default() });
8056 obs.borrow().foo();
8057 },
8058 quote! {
8059 generate!("bar")
8060 subclass!("ObserverA",MyObserverA)
8061 subclass!("ObserverB",MyObserverB)
8062 },
8063 None,
8064 None,
8065 Some(quote! {
8066 use autocxx::subclass::CppSubclass;
8067 use ffi::ObserverA_methods;
8068 use ffi::ObserverB_methods;
8069 #[autocxx::subclass::subclass]
8070 pub struct MyObserverA {
8071 a: u32
8072 }
8073 impl ObserverA_methods for MyObserverA {
8074 }
8075 #[autocxx::subclass::subclass]
8076 pub struct MyObserverB {
8077 a: u32
8078 }
8079 impl ObserverB_methods for MyObserverB {
8080 }
8081 }),
8082 );
8083}
8084
8085#[test]
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07008086fn test_subclass_no_safety() {
8087 let hdr = indoc! {"
8088 #include <cstdint>
8089
8090 class Observer {
8091 public:
8092 Observer() {}
8093 virtual void foo() = 0;
8094 virtual ~Observer() {}
8095 };
8096 "};
8097 let hexathorpe = Token![#](Span::call_site());
8098 let unexpanded_rust = quote! {
8099 use autocxx::prelude::*;
8100
8101 include_cpp!(
8102 #hexathorpe include "input.h"
8103 subclass!("Observer",MyObserver)
8104 );
8105
8106 use ffi::Observer_methods;
8107 #hexathorpe [autocxx::subclass::subclass]
8108 pub struct MyObserver;
8109 impl Observer_methods for MyObserver {
8110 unsafe fn foo(&mut self) {}
8111 }
8112
8113 use autocxx::subclass::{CppSubclass, CppPeerConstructor, CppSubclassRustPeerHolder};
8114 use cxx::UniquePtr;
8115 impl CppPeerConstructor<ffi::MyObserverCpp> for MyObserver {
8116 fn make_peer(
8117 &mut self,
8118 peer_holder: CppSubclassRustPeerHolder<Self>,
8119 ) -> UniquePtr<ffi::MyObserverCpp> {
8120 UniquePtr::emplace(unsafe { ffi::MyObserverCpp::new(peer_holder) })
8121 }
8122 }
8123
8124 fn main() {
8125 let obs = MyObserver::new_rust_owned(MyObserver { cpp_peer: Default::default() });
8126 unsafe { obs.borrow_mut().foo() };
8127 }
8128 };
8129
8130 do_run_test_manual("", hdr, unexpanded_rust, None, None).unwrap()
8131}
8132
8133#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07008134fn test_pv_protected_constructor() {
8135 let hdr = indoc! {"
8136 #include <cstdint>
8137
8138 class Observer {
8139 protected:
8140 Observer() {}
8141 public:
8142 virtual void foo() const {}
8143 virtual ~Observer() {}
8144 };
8145 inline void bar() {}
8146 "};
8147 run_test_ex(
8148 "",
8149 hdr,
8150 quote! {
8151 let obs = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
8152 obs.borrow().foo();
8153 },
8154 quote! {
8155 generate!("bar")
8156 subclass!("Observer",MyObserver)
8157 },
8158 None,
8159 None,
8160 Some(quote! {
8161 use autocxx::subclass::CppSubclass;
8162 use ffi::Observer_methods;
8163 #[autocxx::subclass::subclass]
8164 pub struct MyObserver {
8165 a: u32
8166 }
8167 impl Observer_methods for MyObserver {
8168 }
8169 }),
8170 );
8171}
8172
8173#[test]
8174fn test_pv_protected_method() {
8175 let hdr = indoc! {"
8176 #include <cstdint>
8177
8178 class Observer {
8179 public:
8180 Observer() {}
8181 virtual void foo() const {}
8182 virtual ~Observer() {}
8183 protected:
8184 virtual void baz() const {}
8185 };
8186 inline void bar() {}
8187 "};
8188 run_test_ex(
8189 "",
8190 hdr,
8191 quote! {
8192 let obs = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
8193 obs.borrow().foo();
8194 },
8195 quote! {
8196 generate!("bar")
8197 subclass!("Observer",MyObserver)
8198 },
8199 None,
8200 None,
8201 Some(quote! {
8202 use autocxx::subclass::CppSubclass;
8203 use ffi::Observer_methods;
8204 #[autocxx::subclass::subclass]
8205 pub struct MyObserver {
8206 a: u32
8207 }
8208 impl Observer_methods for MyObserver {
8209 fn baz(&self) {
8210 }
8211
8212 fn foo(&self) {
8213 use ffi::Observer_supers;
8214 self.baz_super()
8215 }
8216 }
8217 }),
8218 );
8219}
8220
8221#[test]
8222fn test_pv_subclass_allocation_not_self_owned() {
8223 let hdr = indoc! {"
8224 #include <cstdint>
8225 extern \"C\" void mark_freed() noexcept;
8226 extern \"C\" void mark_allocated() noexcept;
8227
8228 class TestObserver {
8229 public:
8230 TestObserver() {
8231 mark_allocated();
8232 }
8233 virtual void a() const = 0;
8234 virtual ~TestObserver() {
8235 mark_freed();
8236 }
8237 };
8238 inline void TriggerTestObserverA(const TestObserver& obs) {
8239 obs.a();
8240 }
8241 "};
8242 run_test_ex(
8243 "",
8244 hdr,
8245 quote! {
8246 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8247 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8248 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8249
8250 // Test when owned by C++
8251 let obs = MyTestObserver::new_cpp_owned(
8252 MyTestObserver::new()
8253 );
8254 assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8255 assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8256 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8257 let obs_superclass = obs.as_ref().unwrap(); // &subclass
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008258 let obs_superclass = unsafe { core::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
Brian Silverman4e662aa2022-05-11 23:10:19 -07008259 ffi::TriggerTestObserverA(obs_superclass);
8260 assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008261 core::mem::drop(obs);
Brian Silverman4e662aa2022-05-11 23:10:19 -07008262 Lazy::force(&STATUS).lock().unwrap().a_called = false;
8263 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8264 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8265 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8266
8267 // Test when owned by Rust
8268 let obs = MyTestObserver::new_rust_owned(
8269 MyTestObserver::new()
8270 );
8271 //let cpp_peer_ptr = unsafe { obs.borrow_mut().peer_mut().get_unchecked_mut() as *mut ffi::MyTestObserverCpp };
8272 assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8273 assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8274 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8275 ffi::TriggerTestObserverA(obs.as_ref().borrow().as_ref());
8276 assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
8277 Lazy::force(&STATUS).lock().unwrap().a_called = false;
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008278 core::mem::drop(obs);
Brian Silverman4e662aa2022-05-11 23:10:19 -07008279 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8280 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8281 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8282 },
8283 quote! {
8284 generate!("TriggerTestObserverA")
8285 subclass!("TestObserver",MyTestObserver)
8286 },
8287 None,
8288 None,
8289 Some(quote! {
8290 use once_cell::sync::Lazy;
8291 use std::sync::Mutex;
8292
8293 use autocxx::subclass::CppSubclass;
8294 use ffi::TestObserver_methods;
8295 #[autocxx::subclass::subclass]
8296 pub struct MyTestObserver {
8297 data: ExternalEngine,
8298 }
8299 impl TestObserver_methods for MyTestObserver {
8300 fn a(&self) {
8301 self.data.do_something();
8302 }
8303 }
8304 impl MyTestObserver {
8305 fn new() -> Self {
8306 Self {
8307 cpp_peer: Default::default(),
8308 data: ExternalEngine::default(),
8309 }
8310 }
8311 }
8312
8313 #[no_mangle]
8314 pub fn mark_allocated() {
8315 Lazy::force(&STATUS).lock().unwrap().cpp_allocated = true;
8316 }
8317
8318 #[no_mangle]
8319 pub fn mark_freed() {
8320 Lazy::force(&STATUS).lock().unwrap().cpp_allocated = false;
8321 }
8322
8323 #[derive(Default)]
8324 struct Status {
8325 cpp_allocated: bool,
8326 rust_allocated: bool,
8327 a_called: bool,
8328 }
8329
8330 static STATUS: Lazy<Mutex<Status>> = Lazy::new(|| Mutex::new(Status::default()));
8331
8332 pub struct ExternalEngine;
8333
8334 impl ExternalEngine {
8335 fn do_something(&self) {
8336 Lazy::force(&STATUS).lock().unwrap().a_called = true;
8337 }
8338 }
8339
8340 impl Default for ExternalEngine {
8341 fn default() -> Self {
8342 Lazy::force(&STATUS).lock().unwrap().rust_allocated = true;
8343 ExternalEngine
8344 }
8345 }
8346
8347 impl Drop for ExternalEngine {
8348 fn drop(&mut self) {
8349 Lazy::force(&STATUS).lock().unwrap().rust_allocated = false;
8350 }
8351 }
8352 }),
8353 );
8354}
8355
8356#[test]
8357fn test_pv_subclass_allocation_self_owned() {
8358 let hdr = indoc! {"
8359 #include <cstdint>
8360 extern \"C\" void mark_freed() noexcept;
8361 extern \"C\" void mark_allocated() noexcept;
8362
8363 class TestObserver {
8364 public:
8365 TestObserver() {
8366 mark_allocated();
8367 }
8368 virtual void a() const = 0;
8369 virtual ~TestObserver() {
8370 mark_freed();
8371 }
8372 };
8373 inline void TriggerTestObserverA(const TestObserver& obs) {
8374 const_cast<TestObserver&>(obs).a();
8375 }
8376 "};
8377 run_test_ex(
8378 "",
8379 hdr,
8380 quote! {
8381 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8382 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8383 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8384
8385 // Test when owned by C++
8386 let obs = MyTestObserver::new_cpp_owned(
8387 MyTestObserver::new(false)
8388 );
8389 assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8390 assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8391 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8392 let obs_superclass = obs.as_ref().unwrap(); // &subclass
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008393 let obs_superclass = unsafe { core::mem::transmute::<&ffi::MyTestObserverCpp, &ffi::TestObserver>(obs_superclass) };
Brian Silverman4e662aa2022-05-11 23:10:19 -07008394
8395 ffi::TriggerTestObserverA(obs_superclass);
8396 assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008397 core::mem::drop(obs);
Brian Silverman4e662aa2022-05-11 23:10:19 -07008398 Lazy::force(&STATUS).lock().unwrap().a_called = false;
8399 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8400 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8401 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8402
8403 // Test when owned by Rust
8404 let obs = MyTestObserver::new_rust_owned(
8405 MyTestObserver::new(false)
8406 );
8407 assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8408 assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8409 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8410 ffi::TriggerTestObserverA(obs.as_ref().borrow().as_ref());
8411
8412 assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
8413 Lazy::force(&STATUS).lock().unwrap().a_called = false;
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008414 core::mem::drop(obs);
Brian Silverman4e662aa2022-05-11 23:10:19 -07008415 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8416 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8417 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8418
8419 // Test when self-owned
8420 let obs = MyTestObserver::new_self_owned(
8421 MyTestObserver::new(true)
8422 );
8423 let obs_superclass_ptr: *const ffi::TestObserver = obs.as_ref().borrow().as_ref();
8424 // Retain just a pointer on the Rust side, so there is no Rust-side
8425 // ownership.
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07008426 core::mem::drop(obs);
Brian Silverman4e662aa2022-05-11 23:10:19 -07008427 assert!(Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8428 assert!(Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8429 assert!(!Lazy::force(&STATUS).lock().unwrap().a_called);
8430 ffi::TriggerTestObserverA(unsafe { obs_superclass_ptr.as_ref().unwrap() });
8431
8432 assert!(Lazy::force(&STATUS).lock().unwrap().a_called);
8433 assert!(!Lazy::force(&STATUS).lock().unwrap().rust_allocated);
8434 assert!(!Lazy::force(&STATUS).lock().unwrap().cpp_allocated);
8435 },
8436 quote! {
8437 generate!("TriggerTestObserverA")
8438 subclass!("TestObserver",MyTestObserver)
8439 },
8440 None,
8441 None,
8442 Some(quote! {
8443 use once_cell::sync::Lazy;
8444 use std::sync::Mutex;
8445
8446 use autocxx::subclass::CppSubclass;
8447 use autocxx::subclass::CppSubclassSelfOwned;
8448 use ffi::TestObserver_methods;
8449 #[autocxx::subclass::subclass(self_owned)]
8450 pub struct MyTestObserver {
8451 data: ExternalEngine,
8452 self_owning: bool,
8453 }
8454 impl TestObserver_methods for MyTestObserver {
8455 fn a(&self) {
8456 self.data.do_something();
8457 if self.self_owning {
8458 self.delete_self();
8459 }
8460 }
8461 }
8462 impl MyTestObserver {
8463 fn new(self_owning: bool) -> Self {
8464 Self {
8465 cpp_peer: Default::default(),
8466 data: ExternalEngine::default(),
8467 self_owning,
8468 }
8469 }
8470 }
8471
8472 #[no_mangle]
8473 pub fn mark_allocated() {
8474 Lazy::force(&STATUS).lock().unwrap().cpp_allocated = true;
8475 }
8476
8477 #[no_mangle]
8478 pub fn mark_freed() {
8479 Lazy::force(&STATUS).lock().unwrap().cpp_allocated = false;
8480 }
8481
8482 #[derive(Default)]
8483 struct Status {
8484 cpp_allocated: bool,
8485 rust_allocated: bool,
8486 a_called: bool,
8487 }
8488
8489 static STATUS: Lazy<Mutex<Status>> = Lazy::new(|| Mutex::new(Status::default()));
8490
8491 pub struct ExternalEngine;
8492
8493 impl ExternalEngine {
8494 fn do_something(&self) {
8495 Lazy::force(&STATUS).lock().unwrap().a_called = true;
8496 }
8497 }
8498
8499 impl Default for ExternalEngine {
8500 fn default() -> Self {
8501 Lazy::force(&STATUS).lock().unwrap().rust_allocated = true;
8502 ExternalEngine
8503 }
8504 }
8505
8506 impl Drop for ExternalEngine {
8507 fn drop(&mut self) {
8508 Lazy::force(&STATUS).lock().unwrap().rust_allocated = false;
8509 }
8510 }
8511 }),
8512 );
8513}
8514
8515#[test]
8516fn test_pv_subclass_calls() {
8517 let hdr = indoc! {"
8518 #include <cstdint>
8519 extern \"C\" void mark_c_called() noexcept;
8520 extern \"C\" void mark_d_called() noexcept;
8521 extern \"C\" void mark_e_called() noexcept;
8522 extern \"C\" void mark_f_called() noexcept;
8523 extern \"C\" void mark_g_called() noexcept;
8524 extern \"C\" void mark_h_called() noexcept;
8525
8526 class TestObserver {
8527 public:
8528 TestObserver() {}
8529 virtual uint32_t a(uint32_t) const = 0;
8530 virtual uint32_t b(uint32_t) = 0;
8531 virtual uint32_t c(uint32_t) const { mark_c_called(); return 0; };
8532 virtual uint32_t d(uint32_t) { mark_d_called(); return 0; };
8533 virtual uint32_t e(uint32_t) const { mark_e_called(); return 0; };
8534 virtual uint32_t f(uint32_t) { mark_f_called(); return 0; };
8535 virtual uint32_t g(uint32_t) const { mark_g_called(); return 0; };
8536 virtual uint32_t h(uint32_t) { mark_h_called(); return 0; };
8537 virtual ~TestObserver() {}
8538 };
8539
8540 extern TestObserver* obs;
8541
8542 inline void register_observer(TestObserver& a) {
8543 obs = &a;
8544 }
8545 inline uint32_t call_a(uint32_t param) {
8546 return obs->a(param);
8547 }
8548 inline uint32_t call_b(uint32_t param) {
8549 return obs->b(param);
8550 }
8551 inline uint32_t call_c(uint32_t param) {
8552 return obs->c(param);
8553 }
8554 inline uint32_t call_d(uint32_t param) {
8555 return obs->d(param);
8556 }
8557 inline uint32_t call_e(uint32_t param) {
8558 return obs->e(param);
8559 }
8560 inline uint32_t call_f(uint32_t param) {
8561 return obs->f(param);
8562 }
8563 inline uint32_t call_g(uint32_t param) {
8564 return obs->g(param);
8565 }
8566 inline uint32_t call_h(uint32_t param) {
8567 return obs->h(param);
8568 }
8569 "};
8570 run_test_ex(
8571 "TestObserver* obs;",
8572 hdr,
8573 quote! {
8574 let obs = MyTestObserver::new_rust_owned(
8575 MyTestObserver::default()
8576 );
8577 ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
8578 assert_eq!(ffi::call_a(1), 2);
8579 assert!(Lazy::force(&STATUS).lock().unwrap().sub_a_called);
8580 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8581
8582 assert_eq!(ffi::call_b(1), 3);
8583 assert!(Lazy::force(&STATUS).lock().unwrap().sub_b_called);
8584 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8585
8586 assert_eq!(ffi::call_c(1), 4);
8587 assert!(Lazy::force(&STATUS).lock().unwrap().sub_c_called);
8588 assert!(!Lazy::force(&STATUS).lock().unwrap().super_c_called);
8589 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8590
8591 assert_eq!(ffi::call_d(1), 5);
8592 assert!(Lazy::force(&STATUS).lock().unwrap().sub_d_called);
8593 assert!(!Lazy::force(&STATUS).lock().unwrap().super_d_called);
8594 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8595
8596 assert_eq!(ffi::call_e(1), 0);
8597 assert!(Lazy::force(&STATUS).lock().unwrap().sub_e_called);
8598 assert!(Lazy::force(&STATUS).lock().unwrap().super_e_called);
8599 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8600
8601 assert_eq!(ffi::call_f(1), 0);
8602 assert!(Lazy::force(&STATUS).lock().unwrap().sub_f_called);
8603 assert!(Lazy::force(&STATUS).lock().unwrap().super_f_called);
8604 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8605
8606 assert_eq!(ffi::call_g(1), 0);
8607 assert!(Lazy::force(&STATUS).lock().unwrap().super_g_called);
8608 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8609
8610 assert_eq!(ffi::call_h(1), 0);
8611 assert!(Lazy::force(&STATUS).lock().unwrap().super_h_called);
8612 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8613 },
8614 quote! {
8615 generate!("register_observer")
8616 generate!("call_a")
8617 generate!("call_b")
8618 generate!("call_c")
8619 generate!("call_d")
8620 generate!("call_e")
8621 generate!("call_f")
8622 generate!("call_g")
8623 generate!("call_h")
8624 subclass!("TestObserver",MyTestObserver)
8625 },
8626 None,
8627 None,
8628 Some(quote! {
8629 use once_cell::sync::Lazy;
8630 use std::sync::Mutex;
8631
8632 use autocxx::subclass::CppSubclass;
8633 use ffi::TestObserver_methods;
8634 #[autocxx::subclass::subclass]
8635 #[derive(Default)]
8636 pub struct MyTestObserver {
8637 }
8638 impl TestObserver_methods for MyTestObserver {
8639
8640 // a and b are pure virtual
8641 fn a(&self, param: u32) -> u32 {
8642 Lazy::force(&STATUS).lock().unwrap().sub_a_called = true;
8643 param + 1
8644 }
8645 fn b(&mut self, param: u32) -> u32 {
8646 Lazy::force(&STATUS).lock().unwrap().sub_b_called = true;
8647 param + 2
8648 }
8649
8650 // c and d we override the superclass
8651 fn c(&self, param: u32) -> u32 {
8652 Lazy::force(&STATUS).lock().unwrap().sub_c_called = true;
8653 param + 3
8654 }
8655 fn d(&mut self, param: u32) -> u32 {
8656 Lazy::force(&STATUS).lock().unwrap().sub_d_called = true;
8657 param + 4
8658 }
8659
8660 // e and f we call through to the superclass
8661 fn e(&self, param: u32) -> u32 {
8662 Lazy::force(&STATUS).lock().unwrap().sub_e_called = true;
8663 self.peer().e_super(param)
8664 }
8665 fn f(&mut self, param: u32) -> u32 {
8666 Lazy::force(&STATUS).lock().unwrap().sub_f_called = true;
8667 self.peer_mut().f_super(param)
8668 }
8669
8670 // g and h we do not do anything, so calls should only call
8671 // the superclass
8672 }
8673
8674 #[no_mangle]
8675 pub fn mark_c_called() {
8676 Lazy::force(&STATUS).lock().unwrap().super_c_called = true;
8677 }
8678 #[no_mangle]
8679 pub fn mark_d_called() {
8680 Lazy::force(&STATUS).lock().unwrap().super_d_called = true;
8681 }
8682 #[no_mangle]
8683 pub fn mark_e_called() {
8684 Lazy::force(&STATUS).lock().unwrap().super_e_called = true;
8685 }
8686 #[no_mangle]
8687 pub fn mark_f_called() {
8688 Lazy::force(&STATUS).lock().unwrap().super_f_called = true;
8689 }
8690 #[no_mangle]
8691 pub fn mark_g_called() {
8692 Lazy::force(&STATUS).lock().unwrap().super_g_called = true;
8693 }
8694 #[no_mangle]
8695 pub fn mark_h_called() {
8696 Lazy::force(&STATUS).lock().unwrap().super_h_called = true;
8697 }
8698
8699 #[derive(Default)]
8700 struct Status {
8701 super_c_called: bool,
8702 super_d_called: bool,
8703 super_e_called: bool,
8704 super_f_called: bool,
8705 super_g_called: bool,
8706 super_h_called: bool,
8707 sub_a_called: bool,
8708 sub_b_called: bool,
8709 sub_c_called: bool,
8710 sub_d_called: bool,
8711 sub_e_called: bool,
8712 sub_f_called: bool,
8713 }
8714
8715 static STATUS: Lazy<Mutex<Status>> = Lazy::new(|| Mutex::new(Status::default()));
8716 }),
8717 );
8718}
8719
8720#[test]
Brian Silvermanf3ec38b2022-07-06 20:43:36 -07008721fn test_pv_subclass_as_superclass() {
8722 let hdr = indoc! {"
8723 #include <cstdint>
8724 #include <memory>
8725
8726 class TestObserver {
8727 public:
8728 TestObserver() {}
8729 virtual void a() const = 0;
8730 virtual ~TestObserver() {}
8731 };
8732
8733 inline void call_observer(std::unique_ptr<TestObserver> obs) { obs->a(); }
8734 "};
8735 run_test_ex(
8736 "",
8737 hdr,
8738 quote! {
8739 use autocxx::subclass::CppSubclass;
8740 let obs = MyTestObserver::new_cpp_owned(
8741 MyTestObserver::default()
8742 );
8743 let obs = MyTestObserver::as_TestObserver_unique_ptr(obs);
8744 assert!(!Lazy::force(&STATUS).lock().unwrap().dropped);
8745 ffi::call_observer(obs);
8746 assert!(Lazy::force(&STATUS).lock().unwrap().sub_a_called);
8747 assert!(Lazy::force(&STATUS).lock().unwrap().dropped);
8748 *Lazy::force(&STATUS).lock().unwrap() = Default::default();
8749 },
8750 quote! {
8751 generate!("call_observer")
8752 subclass!("TestObserver",MyTestObserver)
8753 },
8754 None,
8755 None,
8756 Some(quote! {
8757 use once_cell::sync::Lazy;
8758 use std::sync::Mutex;
8759
8760 use ffi::TestObserver_methods;
8761 #[autocxx::subclass::subclass]
8762 #[derive(Default)]
8763 pub struct MyTestObserver {
8764 }
8765 impl TestObserver_methods for MyTestObserver {
8766 fn a(&self) {
8767 assert!(!Lazy::force(&STATUS).lock().unwrap().dropped);
8768 Lazy::force(&STATUS).lock().unwrap().sub_a_called = true;
8769 }
8770 }
8771 impl Drop for MyTestObserver {
8772 fn drop(&mut self) {
8773 Lazy::force(&STATUS).lock().unwrap().dropped = true;
8774 }
8775 }
8776
8777 #[derive(Default)]
8778 struct Status {
8779 sub_a_called: bool,
8780 dropped: bool,
8781 }
8782
8783 static STATUS: Lazy<Mutex<Status>> = Lazy::new(|| Mutex::new(Status::default()));
8784 }),
8785 );
8786}
8787
8788#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07008789fn test_cycle_nonpod_simple() {
8790 let hdr = indoc! {"
8791 #include <string>
8792 struct NonPod {
8793 std::string a;
8794 };
8795 inline NonPod make_non_pod(std::string a) {
8796 NonPod p;
8797 p.a = a;
8798 return p;
8799 }
8800 inline NonPod call_n(NonPod param) {
8801 return param;
8802 }
8803 "};
8804 let rs = quote! {
8805 let nonpod = ffi::make_non_pod("hello").within_unique_ptr();
8806 ffi::call_n(nonpod).within_unique_ptr();
8807 };
8808 run_test("", hdr, rs, &["NonPod", "make_non_pod", "call_n"], &[])
8809}
8810
8811#[test]
8812fn test_pv_subclass_types() {
8813 let hdr = indoc! {"
8814 #include <cstdint>
8815 #include <string>
8816 #include <vector>
8817
8818 struct Fwd;
8819 struct Pod {
8820 uint32_t a;
8821 };
8822 struct NonPod {
8823 std::string a;
8824 };
8825 class TestObserver {
8826 public:
8827 TestObserver() {}
8828 virtual std::string s(std::string p) const { return p; }
8829 virtual Pod p(Pod p) const { return p; }
8830 virtual NonPod n(NonPod p) const { return p; }
8831 virtual void f(const Fwd&) const { }
8832 virtual std::vector<NonPod> v(std::vector<NonPod> v) const { return v; }
8833 virtual const std::vector<NonPod>& vr(const std::vector<NonPod>& vr) const { return vr; }
8834 virtual const std::vector<Fwd>& vfr(const std::vector<Fwd>& vfr) const { return vfr; }
8835 virtual ~TestObserver() {}
8836 };
8837
8838 extern TestObserver* obs;
8839
8840 inline void register_observer(TestObserver& a) {
8841 obs = &a;
8842 }
8843 inline std::string call_s(std::string param) {
8844 return obs->s(param);
8845 }
8846 inline Pod call_p(Pod param) {
8847 return obs->p(param);
8848 }
8849 inline NonPod call_n(NonPod param) {
8850 return obs->n(param);
8851 }
8852 inline NonPod make_non_pod(std::string a) {
8853 NonPod p;
8854 p.a = a;
8855 return p;
8856 }
8857 "};
8858 run_test_ex(
8859 "TestObserver* obs;",
8860 hdr,
8861 quote! {
8862 let obs = MyTestObserver::new_rust_owned(
8863 MyTestObserver::default()
8864 );
8865 ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
8866 ffi::call_p(ffi::Pod { a: 3 });
8867 ffi::call_s("hello");
8868 ffi::call_n(ffi::make_non_pod("goodbye").within_unique_ptr());
8869 },
8870 quote! {
8871 generate!("register_observer")
8872 generate!("call_s")
8873 generate!("call_n")
8874 generate!("call_p")
8875 generate!("NonPod")
8876 generate!("make_non_pod")
8877 generate_pod!("Pod")
8878 subclass!("TestObserver",MyTestObserver)
8879 },
8880 None,
8881 None,
8882 Some(quote! {
8883 use autocxx::subclass::CppSubclass;
8884 use ffi::TestObserver_methods;
8885 #[autocxx::subclass::subclass]
8886 #[derive(Default)]
8887 pub struct MyTestObserver {
8888 }
8889 impl TestObserver_methods for MyTestObserver {
8890 fn s(&self, p: cxx::UniquePtr<cxx::CxxString>) -> cxx::UniquePtr<cxx::CxxString> {
8891 self.peer().s_super(p)
8892 }
8893
8894 fn p(&self, p: ffi::Pod) -> ffi::Pod {
8895 self.peer().p_super(p)
8896 }
8897
8898 fn n(&self, p: cxx::UniquePtr<ffi::NonPod>) -> cxx::UniquePtr<ffi::NonPod> {
8899 self.peer().n_super(p)
8900 }
8901 }
8902 }),
8903 );
8904}
8905
8906#[test]
8907fn test_pv_subclass_constructors() {
8908 // Also tests a Rust-side subclass type which is an empty struct
8909 let hdr = indoc! {"
8910 #include <cstdint>
8911 #include <string>
8912
8913 class TestObserver {
8914 public:
8915 TestObserver() {}
8916 TestObserver(uint8_t) {}
8917 TestObserver(std::string) {}
8918 virtual void call() const { }
8919 virtual ~TestObserver() {}
8920 };
8921
8922 extern TestObserver* obs;
8923
8924 inline void register_observer(TestObserver& a) {
8925 obs = &a;
8926 }
8927 inline void do_a_thing() {
8928 return obs->call();
8929 }
8930 "};
8931 run_test_ex(
8932 "TestObserver* obs;",
8933 hdr,
8934 quote! {
8935 let obs = MyTestObserver::new_rust_owned(
8936 MyTestObserver::default()
8937 );
8938 ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
8939 ffi::do_a_thing();
8940 },
8941 quote! {
8942 generate!("register_observer")
8943 generate!("do_a_thing")
8944 subclass!("TestObserver",MyTestObserver)
8945 },
8946 None,
8947 None,
8948 Some(quote! {
8949 use autocxx::subclass::prelude::*;
8950 #[subclass]
8951 #[derive(Default)]
8952 pub struct MyTestObserver;
8953 impl ffi::TestObserver_methods for MyTestObserver {
8954 fn call(&self) {
8955 self.peer().call_super()
8956 }
8957 }
8958 impl CppPeerConstructor<ffi::MyTestObserverCpp> for MyTestObserver {
8959 fn make_peer(&mut self, peer_holder: CppSubclassRustPeerHolder<Self>) -> cxx::UniquePtr<ffi::MyTestObserverCpp> {
8960 ffi::MyTestObserverCpp::new1(peer_holder, 3u8).within_unique_ptr()
8961 }
8962 }
8963 }),
8964 );
8965}
8966
8967#[test]
8968fn test_pv_subclass_fancy_constructor() {
8969 let hdr = indoc! {"
8970 #include <cstdint>
8971
8972 class Observer {
8973 public:
8974 Observer(uint8_t) {}
8975 virtual uint32_t foo() const = 0;
8976 virtual ~Observer() {}
8977 };
8978 inline void take_observer(const Observer&) {}
8979 "};
8980 run_test_expect_fail_ex(
8981 "",
8982 hdr,
8983 quote! {
8984 let o = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() }, ffi::MyObserverCpp::make_unique);
8985 ffi::take_observer(o.borrow().as_ref());
8986 },
8987 quote! {
8988 generate!("take_observer")
8989 subclass!("Observer",MyObserver)
8990 },
8991 None,
8992 None,
8993 Some(quote! {
8994 use autocxx::subclass::CppSubclass;
8995 use ffi::Observer_methods;
8996 #[autocxx::subclass::subclass]
8997 pub struct MyObserver {
8998 a: u32
8999 }
9000 impl Observer_methods for MyObserver {
9001 fn foo(&self) -> u32 {
9002 4
9003 }
9004 }
9005 }),
9006 );
9007}
9008
9009#[test]
9010fn test_non_pv_subclass_overloads() {
9011 let hdr = indoc! {"
9012 #include <cstdint>
9013 #include <string>
9014
9015 class TestObserver {
9016 public:
9017 TestObserver() {}
9018 virtual void call(uint8_t) const {}
9019 virtual void call(std::string) const {}
9020 virtual ~TestObserver() {}
9021 };
9022
9023 extern TestObserver* obs;
9024
9025 inline void register_observer(TestObserver& a) {
9026 obs = &a;
9027 }
9028 inline void do_a_thing() {
9029 return obs->call(8);
9030 }
9031 "};
9032 run_test_ex(
9033 "TestObserver* obs;",
9034 hdr,
9035 quote! {
9036 let obs = MyTestObserver::new_rust_owned(
9037 MyTestObserver::default()
9038 );
9039 ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
9040 ffi::do_a_thing();
9041 },
9042 quote! {
9043 generate!("register_observer")
9044 generate!("do_a_thing")
9045 subclass!("TestObserver",MyTestObserver)
9046 },
9047 None,
9048 None,
9049 Some(quote! {
9050 use autocxx::subclass::prelude::*;
9051 #[subclass]
9052 #[derive(Default)]
9053 pub struct MyTestObserver;
9054 impl ffi::TestObserver_methods for MyTestObserver {
9055 fn call(&self, a: u8) {
9056 self.peer().call_super(a)
9057 }
9058 fn call1(&self, a: cxx::UniquePtr<cxx::CxxString>) {
9059 self.peer().call1_super(a)
9060 }
9061 }
9062 }),
9063 );
9064}
9065
9066#[test]
9067fn test_pv_subclass_overrides() {
9068 let hdr = indoc! {"
9069 #include <cstdint>
9070 #include <string>
9071
9072 class TestObserver {
9073 public:
9074 TestObserver() {}
9075 virtual void call(uint8_t) const = 0;
9076 virtual void call(std::string) const = 0;
9077 virtual ~TestObserver() {}
9078 };
9079
9080 extern TestObserver* obs;
9081
9082 inline void register_observer(TestObserver& a) {
9083 obs = &a;
9084 }
9085 inline void do_a_thing() {
9086 return obs->call(8);
9087 }
9088 "};
9089 run_test_ex(
9090 "TestObserver* obs;",
9091 hdr,
9092 quote! {
9093 let obs = MyTestObserver::new_rust_owned(
9094 MyTestObserver::default()
9095 );
9096 ffi::register_observer(obs.as_ref().borrow_mut().pin_mut());
9097 ffi::do_a_thing();
9098 },
9099 quote! {
9100 generate!("register_observer")
9101 generate!("do_a_thing")
9102 subclass!("TestObserver",MyTestObserver)
9103 },
9104 None,
9105 None,
9106 Some(quote! {
9107 use autocxx::subclass::prelude::*;
9108 #[subclass]
9109 #[derive(Default)]
9110 pub struct MyTestObserver;
9111 impl ffi::TestObserver_methods for MyTestObserver {
9112 fn call(&self, _a: u8) {
9113 }
9114 fn call1(&self, _a: cxx::UniquePtr<cxx::CxxString>) {
9115 }
9116 }
9117 }),
9118 );
9119}
9120
9121#[test]
9122fn test_pv_subclass_namespaced_superclass() {
9123 let hdr = indoc! {"
9124 #include <cstdint>
9125
9126 namespace a {
9127 class Observer {
9128 public:
9129 Observer() {}
9130 virtual uint32_t foo() const = 0;
9131 virtual ~Observer() {}
9132 };
9133 }
9134 inline void take_observer(const a::Observer&) {}
9135 "};
9136 run_test_ex(
9137 "",
9138 hdr,
9139 quote! {
9140 let o = MyObserver::new_rust_owned(MyObserver { a: 3, cpp_peer: Default::default() });
9141 ffi::take_observer(o.borrow().as_ref());
9142 },
9143 quote! {
9144 generate!("take_observer")
9145 subclass!("a::Observer",MyObserver)
9146 },
9147 None,
9148 None,
9149 Some(quote! {
9150 use autocxx::subclass::CppSubclass;
9151 #[autocxx::subclass::subclass]
9152 pub struct MyObserver {
9153 a: u32
9154 }
9155 impl ffi::a::Observer_methods for MyObserver {
9156 fn foo(&self) -> u32 {
9157 4
9158 }
9159 }
9160 }),
9161 );
9162}
9163
9164#[test]
9165fn test_no_constructor_make_unique() {
9166 let hdr = indoc! {"
9167 #include <stdint.h>
9168 struct A {
9169 uint32_t a;
9170 };
9171 "};
9172 let rs = quote! {
9173 ffi::A::new().within_unique_ptr();
9174 };
9175 run_test("", hdr, rs, &["A"], &[]);
9176}
9177
9178#[test]
9179fn test_constructor_moveit() {
9180 let hdr = indoc! {"
9181 #include <stdint.h>
9182 #include <string>
9183 struct A {
9184 A() {}
9185 void set(uint32_t val) { a = val; }
9186 uint32_t get() const { return a; }
9187 uint32_t a;
9188 std::string so_we_are_non_trivial;
9189 };
9190 "};
9191 let rs = quote! {
9192 moveit! {
9193 let mut stack_obj = ffi::A::new();
9194 }
9195 stack_obj.as_mut().set(42);
9196 assert_eq!(stack_obj.get(), 42);
9197 };
9198 run_test("", hdr, rs, &["A"], &[]);
9199}
9200
9201#[test]
9202fn test_move_out_of_uniqueptr() {
9203 let hdr = indoc! {"
9204 #include <stdint.h>
9205 #include <string>
9206 struct A {
9207 A() {}
9208 std::string so_we_are_non_trivial;
9209 };
9210 inline A get_a() {
9211 A a;
9212 return a;
9213 }
9214 "};
9215 let rs = quote! {
9216 let a = ffi::get_a().within_unique_ptr();
9217 moveit! {
9218 let _stack_obj = autocxx::moveit::new::mov(a);
9219 }
9220 };
9221 run_test("", hdr, rs, &["A", "get_a"], &[]);
9222}
9223
9224#[test]
9225fn test_implicit_constructor_with_typedef_field() {
9226 let hdr = indoc! {"
9227 #include <stdint.h>
9228 #include <string>
9229 struct B {
9230 uint32_t b;
9231 };
9232 typedef struct B C;
9233 struct A {
9234 B field;
9235 uint32_t a;
9236 std::string so_we_are_non_trivial;
9237 };
9238 "};
9239 let rs = quote! {
9240 moveit! {
9241 let mut stack_obj = ffi::A::new();
9242 }
9243 };
9244 run_test("", hdr, rs, &["A"], &[]);
9245}
9246
9247#[test]
9248fn test_implicit_constructor_with_array_field() {
9249 let hdr = indoc! {"
9250 #include <stdint.h>
9251 #include <string>
9252 struct A {
9253 uint32_t a[3];
9254 std::string so_we_are_non_trivial;
9255 };
9256 "};
9257 let rs = quote! {
9258 moveit! {
9259 let mut _stack_obj = ffi::A::new();
9260 }
9261 };
9262 run_test("", hdr, rs, &["A"], &[]);
9263}
9264
9265#[test]
9266fn test_implicit_constructor_moveit() {
9267 let hdr = indoc! {"
9268 #include <stdint.h>
9269 #include <string>
9270 struct A {
9271 void set(uint32_t val) { a = val; }
9272 uint32_t get() const { return a; }
9273 uint32_t a;
9274 std::string so_we_are_non_trivial;
9275 };
9276 "};
9277 let rs = quote! {
9278 moveit! {
9279 let mut stack_obj = ffi::A::new();
9280 }
9281 stack_obj.as_mut().set(42);
9282 assert_eq!(stack_obj.get(), 42);
9283 };
9284 run_test("", hdr, rs, &["A"], &[]);
9285}
9286
9287#[test]
9288fn test_pass_by_value_moveit() {
9289 let hdr = indoc! {"
9290 #include <stdint.h>
9291 #include <string>
9292 struct A {
9293 void set(uint32_t val) { a = val; }
9294 uint32_t a;
9295 std::string so_we_are_non_trivial;
9296 };
9297 inline void take_a(A) {}
9298 struct B {
9299 B() {}
9300 B(const B&) {}
9301 B(B&&) {}
9302 std::string so_we_are_non_trivial;
9303 };
9304 inline void take_b(B) {}
9305 "};
9306 let rs = quote! {
9307 moveit! {
9308 let mut stack_obj = ffi::A::new();
9309 }
9310 stack_obj.as_mut().set(42);
9311 ffi::take_a(&*stack_obj);
9312 ffi::take_a(as_copy(stack_obj.as_ref()));
9313 ffi::take_a(as_copy(stack_obj.as_ref()));
9314 // A has no move constructor so we can't consume it.
9315
9316 let heap_obj = ffi::A::new().within_unique_ptr();
9317 ffi::take_a(heap_obj.as_ref().unwrap());
9318 ffi::take_a(&heap_obj);
9319 ffi::take_a(autocxx::as_copy(heap_obj.as_ref().unwrap()));
9320 ffi::take_a(heap_obj); // consume
9321
9322 let heap_obj2 = ffi::A::new().within_box();
9323 ffi::take_a(heap_obj2.as_ref().get_ref());
9324 ffi::take_a(&heap_obj2);
9325 ffi::take_a(autocxx::as_copy(heap_obj2.as_ref().get_ref()));
9326 ffi::take_a(heap_obj2); // consume
9327
9328 moveit! {
9329 let mut stack_obj = ffi::B::new();
9330 }
9331 ffi::take_b(&*stack_obj);
9332 ffi::take_b(as_copy(stack_obj.as_ref()));
9333 ffi::take_b(as_copy(stack_obj.as_ref()));
9334 ffi::take_b(as_mov(stack_obj)); // due to move constructor
9335
9336 // Test direct-from-New-to-param.
9337 ffi::take_b(as_new(ffi::B::new()));
9338 };
9339 run_test("", hdr, rs, &["A", "take_a", "B", "take_b"], &[]);
9340}
9341
9342#[test]
9343fn test_nonconst_reference_parameter() {
9344 let hdr = indoc! {"
9345 #include <stdint.h>
9346 #include <string>
9347
9348 // Force generating a wrapper for the second `take_a`.
9349 struct NOP { void take_a() {}; };
9350
9351 struct A {
9352 std::string so_we_are_non_trivial;
9353 };
9354 inline void take_a(A&) {}
9355 "};
9356 let rs = quote! {
9357 let mut heap_obj = ffi::A::new().within_unique_ptr();
9358 ffi::take_a(heap_obj.pin_mut());
9359 };
9360 run_test("", hdr, rs, &["NOP", "A", "take_a"], &[]);
9361}
9362
9363#[test]
9364fn test_nonconst_reference_method_parameter() {
9365 let hdr = indoc! {"
9366 #include <stdint.h>
9367 #include <string>
9368
9369 // Force generating a wrapper for the second `take_a`.
9370 struct NOP { void take_a() {}; };
9371
9372 struct A {
9373 std::string so_we_are_non_trivial;
9374 };
9375 struct B {
9376 inline void take_a(A&) const {}
9377 };
9378 "};
9379 let rs = quote! {
9380 let mut a = ffi::A::new().within_unique_ptr();
9381 let b = ffi::B::new().within_unique_ptr();
9382 b.take_a(a.pin_mut());
9383 };
9384 run_test("", hdr, rs, &["NOP", "A", "B"], &[]);
9385}
9386
9387fn destruction_test(ident: proc_macro2::Ident, extra_bit: Option<TokenStream>) {
9388 let hdr = indoc! {"
9389 #include <stdint.h>
9390 #include <string>
9391 extern bool gConstructed;
9392 struct A {
9393 A() { gConstructed = true; }
9394 virtual ~A() { gConstructed = false; }
9395 void set(uint32_t val) { a = val; }
9396 uint32_t get() const { return a; }
9397 uint32_t a;
9398 std::string so_we_are_non_trivial;
9399 };
9400 inline bool is_constructed() { return gConstructed; }
9401 struct B: public A {
9402 uint32_t b;
9403 };
9404 "};
9405 let cpp = indoc! {"
9406 bool gConstructed = false;
9407 "};
9408 let rs = quote! {
9409 assert!(!ffi::is_constructed());
9410 {
9411 moveit! {
9412 let mut _stack_obj = ffi::#ident::new();
9413 }
9414 assert!(ffi::is_constructed());
9415 #extra_bit
9416 }
9417 assert!(!ffi::is_constructed());
9418 };
9419 run_test(cpp, hdr, rs, &[&ident.to_string(), "is_constructed"], &[]);
9420}
9421
9422#[test]
9423fn test_destructor_moveit() {
9424 destruction_test(
9425 parse_quote! { A },
9426 Some(quote! {
9427 _stack_obj.as_mut().set(42);
9428 assert_eq!(_stack_obj.get(), 42);
9429 }),
9430 );
9431}
9432
9433#[test]
9434fn test_destructor_derived_moveit() {
9435 destruction_test(parse_quote! { B }, None);
9436}
9437
9438#[test]
9439fn test_copy_and_move_constructor_moveit() {
9440 let hdr = indoc! {"
9441 #include <stdint.h>
9442 #include <string>
9443 struct A {
9444 A() {}
9445 A(const A& other) : a(other.a+1) {}
9446 A(A&& other) : a(other.a+2) { other.a = 666; }
9447 void set(uint32_t val) { a = val; }
9448 uint32_t get() const { return a; }
9449 uint32_t a;
9450 std::string so_we_are_non_trivial;
9451 };
9452 "};
9453 let rs = quote! {
9454 moveit! {
9455 let mut stack_obj = ffi::A::new();
9456 }
9457 stack_obj.as_mut().set(42);
9458 moveit! {
9459 let stack_obj2 = autocxx::moveit::new::copy(stack_obj.as_ref());
9460 }
9461 assert_eq!(stack_obj2.get(), 43);
9462 assert_eq!(stack_obj.get(), 42);
9463 moveit! {
9464 let stack_obj3 = autocxx::moveit::new::mov(stack_obj);
9465 }
9466 assert_eq!(stack_obj3.get(), 44);
9467 // Following line prevented by moveit, even though it would
9468 // be possible in C++.
9469 // assert_eq!(stack_obj.get(), 666);
9470 };
9471 run_test("", hdr, rs, &["A"], &[]);
9472}
9473
9474// This test fails on Windows gnu but not on Windows msvc
9475#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
9476#[test]
9477fn test_uniqueptr_moveit() {
9478 let hdr = indoc! {"
9479 #include <stdint.h>
9480 #include <string>
9481 struct A {
9482 A() {}
9483 void set(uint32_t val) { a = val; }
9484 uint32_t get() const { return a; }
9485 uint32_t a;
9486 std::string so_we_are_non_trivial;
9487 };
9488 "};
9489 let rs = quote! {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009490 use autocxx::moveit::Emplace;
Brian Silverman4e662aa2022-05-11 23:10:19 -07009491 let mut up_obj = cxx::UniquePtr::emplace(ffi::A::new());
9492 up_obj.as_mut().unwrap().set(42);
9493 assert_eq!(up_obj.get(), 42);
9494 };
9495 run_test("", hdr, rs, &["A"], &[]);
9496}
9497
9498// This test fails on Windows gnu but not on Windows msvc
9499#[cfg_attr(skip_windows_gnu_failing_tests, ignore)]
9500#[test]
9501fn test_various_emplacement() {
9502 let hdr = indoc! {"
9503 #include <stdint.h>
9504 #include <string>
9505 struct A {
9506 A() {}
9507 void set(uint32_t val) { a = val; }
9508 uint32_t get() const { return a; }
9509 uint32_t a;
9510 std::string so_we_are_non_trivial;
9511 };
9512 "};
9513 let rs = quote! {
Brian Silverman4e662aa2022-05-11 23:10:19 -07009514 use autocxx::moveit::Emplace;
9515 let mut up_obj = cxx::UniquePtr::emplace(ffi::A::new());
9516 up_obj.pin_mut().set(666);
9517 // Can't current move out of a UniquePtr
9518 let mut box_obj = Box::emplace(ffi::A::new());
9519 box_obj.as_mut().set(667);
9520 let box_obj2 = Box::emplace(autocxx::moveit::new::mov(box_obj));
9521 moveit! { let back_on_stack = autocxx::moveit::new::mov(box_obj2); }
9522 assert_eq!(back_on_stack.get(), 667);
9523 };
9524 run_test("", hdr, rs, &["A"], &[]);
9525}
9526
9527#[test]
9528fn test_emplace_uses_overridden_new_and_delete() {
9529 let hdr = indoc! {"
9530 #include <stdint.h>
9531 #include <string>
9532 struct A {
9533 A() {}
9534 void* operator new(size_t count);
9535 void operator delete(void* ptr) noexcept;
9536 void* operator new(size_t count, void* ptr);
9537 std::string so_we_are_non_trivial;
9538 };
9539 void reset_flags();
9540 bool was_new_called();
9541 bool was_delete_called();
9542 "};
9543 let cxx = indoc! {"
9544 bool new_called;
9545 bool delete_called;
9546 void reset_flags() {
9547 new_called = false;
9548 delete_called = false;
9549 }
9550 void* A::operator new(size_t count) {
9551 new_called = true;
9552 return ::operator new(count);
9553 }
9554 void* A::operator new(size_t count, void* ptr) {
9555 return ::operator new(count, ptr);
9556 }
9557 void A::operator delete(void* ptr) noexcept {
9558 delete_called = true;
9559 ::operator delete(ptr);
9560 }
9561 bool was_new_called() {
9562 return new_called;
9563 }
9564 bool was_delete_called() {
9565 return delete_called;
9566 }
9567 "};
9568 let rs = quote! {
9569 ffi::reset_flags();
9570 {
9571 let _ = ffi::A::new().within_unique_ptr();
9572 assert!(ffi::was_new_called());
9573 }
9574 assert!(ffi::was_delete_called());
9575 ffi::reset_flags();
9576 {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009577 use autocxx::moveit::Emplace;
Brian Silverman4e662aa2022-05-11 23:10:19 -07009578 let _ = cxx::UniquePtr::emplace(ffi::A::new());
9579 }
9580 assert!(ffi::was_delete_called());
9581 };
9582 run_test(
9583 cxx,
9584 hdr,
9585 rs,
9586 &["A", "reset_flags", "was_new_called", "was_delete_called"],
9587 &[],
9588 );
9589}
9590
9591#[test]
9592fn test_pass_by_reference_to_value_param() {
9593 let hdr = indoc! {"
9594 #include <stdint.h>
9595 #include <string>
9596 struct A {
9597 A() : count(0) {}
9598 std::string so_we_are_non_trivial;
9599 uint32_t count;
9600 };
9601 void take_a(A a) {
9602 a.count++;
9603 }
9604 uint32_t report_on_a(const A& a) {
9605 return a.count;
9606 }
9607 "};
9608 let rs = quote! {
9609 let a = ffi::A::new().within_unique_ptr();
9610 ffi::take_a(a.as_ref().unwrap());
9611 ffi::take_a(&a); // syntactic sugar
9612 assert_eq!(ffi::report_on_a(&a), 0); // should have acted upon copies
9613 };
9614 run_test("", hdr, rs, &["A", "take_a", "report_on_a"], &[]);
9615}
9616
9617#[test]
9618fn test_explicit_everything() {
9619 let hdr = indoc! {"
9620 #include <stdint.h>
9621 #include <string>
9622 struct A {
9623 A() {} // default constructor
9624 A(A&&) {} // move constructor
9625 A(const A&) {} // copy constructor
9626 A& operator=(const A&) { return *this; } // copy assignment operator
9627 A& operator=(A&&) { return *this; } // move assignment operator
9628 ~A() {} // destructor
9629 void set(uint32_t val) { a = val; }
9630 uint32_t get() const { return a; }
9631 uint32_t a;
9632 std::string so_we_are_non_trivial;
9633 };
9634 "};
9635 let rs = quote! {};
9636 run_test("", hdr, rs, &["A"], &[]);
9637}
9638
9639#[test]
9640fn test_generate_ns() {
9641 let hdr = indoc! {"
9642 namespace A {
9643 inline void foo() {}
9644 inline void bar() {}
9645 }
9646 namespace B {
9647 inline void baz() {}
9648 }
9649 "};
9650 let rs = quote! {
9651 ffi::A::foo();
9652 };
9653 run_test_ex(
9654 "",
9655 hdr,
9656 rs,
9657 quote! {
9658 generate_ns!("A")
9659 safety!(unsafe_ffi)
9660 },
9661 None,
9662 None,
9663 None,
9664 );
9665}
9666
9667#[test]
9668fn test_no_constructor_make_unique_ns() {
9669 let hdr = indoc! {"
9670 #include <stdint.h>
9671 namespace B {
9672 struct A {
9673 uint32_t a;
9674 };
9675 }
9676 "};
9677 let rs = quote! {
9678 ffi::B::A::new().within_unique_ptr();
9679 };
9680 run_test("", hdr, rs, &["B::A"], &[]);
9681}
9682
9683#[test]
9684fn test_no_constructor_pod_make_unique() {
9685 let hdr = indoc! {"
9686 #include <stdint.h>
9687 struct A {
9688 uint32_t a;
9689 };
9690 "};
9691 let rs = quote! {
9692 ffi::A::new().within_unique_ptr();
9693 };
9694 run_test("", hdr, rs, &[], &["A"]);
9695}
9696
9697#[test]
9698fn test_no_constructor_pv() {
9699 let hdr = indoc! {"
9700 #include <stdint.h>
9701 class A {
9702 public:
9703 virtual ~A() {}
9704 virtual void foo() = 0;
9705 };
9706 "};
9707 let rs = quote! {};
9708 run_test("", hdr, rs, &["A"], &[]);
9709}
9710
9711#[test]
9712fn test_suppress_system_includes() {
9713 let hdr = indoc! {"
9714 #include <stdint.h>
9715 #include <string>
9716 inline void a() {};
9717 "};
9718 let rs = quote! {};
9719 run_test_ex(
9720 "",
9721 hdr,
9722 rs,
9723 quote! { generate("a")},
9724 Some(Box::new(SetSuppressSystemHeaders)),
9725 Some(Box::new(NoSystemHeadersChecker)),
9726 None,
9727 );
9728}
9729
9730#[test]
9731fn test_no_rvo_move() {
9732 let hdr = indoc! {"
9733 #include <memory>
9734 class A {
9735 public:
9736 static std::unique_ptr<A> create() { return std::make_unique<A>(); }
9737 };
9738 "};
9739 let rs = quote! {
9740 ffi::A::create();
9741 };
9742 run_test_ex(
9743 "",
9744 hdr,
9745 rs,
9746 quote! { generate!("A") },
9747 None,
9748 Some(Box::new(CppMatcher::new(
9749 &["return A::create();"],
9750 &["return std::move(A::create());"],
9751 ))),
9752 None,
9753 );
9754}
9755
9756#[test]
9757fn test_abstract_up() {
9758 let hdr = indoc! {"
9759 #include <memory>
9760 class A {
9761 public:
9762 virtual void foo() const = 0;
9763 virtual ~A() {}
9764 };
9765 class B : public A {
9766 public:
9767 void foo() const {}
9768 };
9769 inline std::unique_ptr<A> get_a() { return std::make_unique<B>(); }
9770 "};
9771 let rs = quote! {
9772 let a = ffi::get_a();
9773 a.foo();
9774 };
9775 run_test("", hdr, rs, &["A", "get_a"], &[]);
9776}
9777
9778#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009779fn test_abstract_up_multiple_bridge() {
9780 let hdr = indoc! {"
9781 #include <memory>
9782 class A {
9783 public:
9784 virtual void foo() const = 0;
9785 virtual ~A() {}
9786 };
9787 class B : public A {
9788 public:
9789 void foo() const {}
9790 };
9791 inline std::unique_ptr<A> get_a() { return std::make_unique<B>(); }
9792 "};
9793 let hexathorpe = Token![#](Span::call_site());
9794 let rs = quote! {
9795 autocxx::include_cpp! {
9796 #hexathorpe include "input.h"
9797 safety!(unsafe_ffi)
9798 generate!("A")
9799 }
9800 autocxx::include_cpp! {
9801 #hexathorpe include "input.h"
9802 safety!(unsafe_ffi)
9803 name!(ffi2)
9804 extern_cpp_type!("A", crate::ffi::A)
9805 generate!("get_a")
9806 }
9807 fn main() {
9808 let a = ffi2::get_a();
9809 a.foo();
9810 }
9811 };
9812 do_run_test_manual("", hdr, rs, None, None).unwrap();
9813}
9814
9815#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -07009816fn test_abstract_private() {
9817 let hdr = indoc! {"
9818 #include <memory>
9819 class A {
9820 virtual void foo() const = 0;
9821 public:
9822 virtual ~A() {}
9823 };
9824 "};
9825 let rs = quote! {};
9826 run_test("", hdr, rs, &["A"], &[]);
9827}
9828
9829#[test]
9830fn test_abstract_issue_979() {
9831 let hdr = indoc! {"
9832 class Test {
9833 virtual ~Test() {}
9834 virtual void TestBody() = 0;
9835 };
9836 "};
9837 let rs = quote! {};
9838 run_test("", hdr, rs, &["Test"], &[]);
9839}
9840
9841#[test]
9842fn test_class_having_protected_method() {
9843 let hdr = indoc! {"
9844 #include <cstdint>
9845 class A {
9846 protected:
9847 inline uint32_t protected_method() { return 0; }
9848 };
9849 "};
9850 let rs = quote! {};
9851 run_test("", hdr, rs, &[], &["A"]);
9852}
9853
9854#[test]
9855fn test_protected_inner_class() {
9856 let hdr = indoc! {"
9857 #include <cstdint>
9858 inline uint32_t DoMath(uint32_t a) {
9859 return a * 3;
9860 }
9861
9862 class A {
9863 protected:
9864 inline uint32_t protected_method() { return 0; }
9865
9866 struct B {
9867 int x;
9868 };
9869
9870 inline B protected_method_2() {
9871 return { 0 };
9872 }
9873 };
9874 "};
9875 let rs = quote! {};
9876 run_test("", hdr, rs, &["A"], &[]);
9877}
9878
9879#[test]
9880fn test_private_inner_class() {
9881 let hdr = indoc! {"
9882 #include <cstdint>
9883 inline uint32_t DoMath(uint32_t a) {
9884 return a * 3;
9885 }
9886
9887 class A {
9888 protected:
9889 inline uint32_t protected_method() { return 0; }
9890
9891 private:
9892 struct B {
9893 int x;
9894 };
9895
9896 inline B private_method_2() {
9897 return { 0 };
9898 }
9899 };
9900 "};
9901 let rs = quote! {};
9902 run_test("", hdr, rs, &["A"], &[]);
9903}
9904
9905#[test]
9906fn test_class_having_private_method() {
9907 let hdr = indoc! {"
9908 #include <cstdint>
9909 class A {
9910 private:
9911 inline uint32_t private_method() { return 0; }
9912 };
9913 "};
9914 let rs = quote! {};
9915 run_test("", hdr, rs, &[], &["A"]);
9916}
9917
9918#[test]
9919#[ignore] // https://github.com/google/autocxx/issues/787
9920fn test_chrono_problem() {
9921 let hdr = indoc! {"
9922 #include <chrono>
9923 struct Clock {
9924 typedef std::chrono::nanoseconds duration;
9925 };
9926 struct Class {
9927 int a() { return 42; }
9928 std::chrono::time_point<Clock> b();
9929 };
9930 "};
9931 let rs = quote! {};
9932 run_test("", hdr, rs, &[], &["Class"]);
9933}
9934
9935fn size_and_alignment_test(pod: bool) {
9936 static TYPES: [(&str, &str); 6] = [
9937 ("A", "struct A { uint8_t a; };"),
9938 ("B", "struct B { uint32_t a; };"),
9939 ("C", "struct C { uint64_t a; };"),
9940 ("D", "enum D { Z, X };"),
9941 ("E", "struct E { uint8_t a; uint32_t b; };"),
9942 ("F", "struct F { uint32_t a; uint8_t b; };"),
9943 ];
9944 let type_definitions = TYPES.iter().map(|(_, def)| *def).join("\n");
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009945 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 -07009946 let hdr = format!(
9947 indoc! {"
9948 #include <cstdint>
9949 #include <cstddef>
9950 {}
9951 {}
9952 "},
9953 type_definitions, function_definitions
9954 );
9955 #[allow(clippy::unnecessary_to_owned)] // wrongly triggers on into_iter() below
9956 let allowlist_fns: Vec<String> = TYPES
9957 .iter()
9958 .flat_map(|(name, _)| {
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009959 [format!("get_sizeof_{name}"), format!("get_alignof_{name}")]
9960 .to_vec()
9961 .into_iter()
Brian Silverman4e662aa2022-05-11 23:10:19 -07009962 })
9963 .collect_vec();
9964 let allowlist_types: Vec<String> = TYPES.iter().map(|(name, _)| name.to_string()).collect_vec();
9965 let allowlist_both = allowlist_types
9966 .iter()
9967 .cloned()
9968 .chain(allowlist_fns.iter().cloned())
9969 .collect_vec();
9970 let allowlist_types: Vec<&str> = allowlist_types.iter().map(AsRef::as_ref).collect_vec();
9971 let allowlist_fns: Vec<&str> = allowlist_fns.iter().map(AsRef::as_ref).collect_vec();
9972 let allowlist_both: Vec<&str> = allowlist_both.iter().map(AsRef::as_ref).collect_vec();
9973 let rs = TYPES.iter().fold(quote! {}, |mut accumulator, (name, _)| {
9974 let get_align_symbol =
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009975 proc_macro2::Ident::new(&format!("get_alignof_{name}"), Span::call_site());
Brian Silverman4e662aa2022-05-11 23:10:19 -07009976 let get_size_symbol =
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009977 proc_macro2::Ident::new(&format!("get_sizeof_{name}"), Span::call_site());
Brian Silverman4e662aa2022-05-11 23:10:19 -07009978 let type_symbol = proc_macro2::Ident::new(name, Span::call_site());
9979 accumulator.extend(quote! {
9980 let c_size = ffi::#get_size_symbol();
9981 let c_align = ffi::#get_align_symbol();
Austin Schuh6ea9bfa2023-08-06 19:05:10 -07009982 assert_eq!(core::mem::size_of::<ffi::#type_symbol>(), c_size);
9983 assert_eq!(core::mem::align_of::<ffi::#type_symbol>(), c_align);
Brian Silverman4e662aa2022-05-11 23:10:19 -07009984 });
9985 accumulator
9986 });
9987 if pod {
9988 run_test("", &hdr, rs, &allowlist_fns, &allowlist_types);
9989 } else {
9990 run_test("", &hdr, rs, &allowlist_both, &[]);
9991 }
9992}
9993
9994#[test]
9995fn test_sizes_and_alignment_nonpod() {
9996 size_and_alignment_test(false)
9997}
9998
9999#[test]
10000fn test_sizes_and_alignment_pod() {
10001 size_and_alignment_test(true)
10002}
10003
10004#[test]
10005fn test_nested_class_methods() {
10006 let hdr = indoc! {"
10007 #include <cstdint>
10008 class A {
10009 public:
10010 virtual ~A() {}
10011 struct B {
10012 virtual void b() const {}
10013 };
10014 virtual void a() const {}
10015 struct C {
10016 virtual void b() const {}
10017 };
10018 virtual void c() const {}
10019 struct D {
10020 virtual void b() const {}
10021 };
10022 };
10023 "};
10024 let rs = quote! {
10025 let a = ffi::A::new().within_unique_ptr();
10026 a.a();
10027 a.c();
10028 };
10029 run_test("", hdr, rs, &["A"], &[]);
10030}
10031
10032#[test]
10033fn test_call_superclass() {
10034 let hdr = indoc! {"
10035 #include <memory>
10036 class A {
10037 public:
10038 virtual void foo() const {};
10039 virtual ~A() {}
10040 };
10041 class B : public A {
10042 public:
10043 void bar() const {}
10044 };
10045 inline std::unique_ptr<B> get_b() { return std::make_unique<B>(); }
10046 "};
10047 let rs = quote! {
10048 let b = ffi::get_b();
10049 b.as_ref().unwrap().as_ref().foo();
10050 };
10051 run_test("", hdr, rs, &["A", "B", "get_b"], &[]);
10052}
10053
10054#[test]
10055fn test_pass_superclass() {
10056 let hdr = indoc! {"
10057 #include <memory>
10058 class A {
10059 public:
10060 virtual void foo() const {};
10061 virtual ~A() {}
10062 };
10063 class B : public A {
10064 public:
10065 void bar() const {}
10066 };
10067 inline std::unique_ptr<B> get_b() { return std::make_unique<B>(); }
10068 inline void take_a(const A&) {}
10069 "};
10070 let rs = quote! {
10071 let b = ffi::get_b();
10072 ffi::take_a(b.as_ref().unwrap().as_ref());
10073 };
10074 run_test("", hdr, rs, &["A", "B", "get_b", "take_a"], &[]);
10075}
10076
10077#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070010078fn test_issue_1238() {
10079 let hdr = indoc! {"
10080 class b;
10081 class c;
10082 class f {
10083 b d();
10084 };
10085 class S2E {
10086 public:
10087 f e;
10088 b &d(c *) const;
10089 };
10090 "};
10091 let rs = quote! {};
10092 run_test("", hdr, rs, &["S2E"], &[]);
10093}
10094
10095#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -070010096fn test_issue486_multi_types() {
10097 let hdr = indoc! {"
10098 namespace a {
10099 namespace spanner {
10100 struct Key {};
10101 }
10102 } // namespace a
10103 namespace b {
10104 namespace spanner {
10105 typedef int Key;
10106 }
10107 } // namespace b
10108 namespace c {
10109 namespace spanner {
10110 enum Key { A, B };
10111 }
10112 } // namespace c
10113 namespace spanner {
10114 class Key {
10115 public:
10116 bool a(a::spanner::Key &);
10117 bool b(b::spanner::Key &);
10118 bool c(c::spanner::Key &);
10119 };
10120 } // namespace spanner
10121 "};
10122 let rs = quote! {};
10123 run_test(
10124 "",
10125 hdr,
10126 rs,
10127 &["spanner::Key", "a::spanner::Key", "b::spanner::Key"],
10128 &[],
10129 );
10130}
10131
10132#[test]
10133/// Tests types with various forms of copy, move, and default constructors. Calls the things which
10134/// should be generated, and will produce C++ compile failures if other wrappers are generated.
10135///
10136/// Specifically, we can have the cross product of any of these:
10137/// * Explicitly deleted
10138/// * Implicitly defaulted
10139/// * User declared
10140/// * Explicitly defaulted
10141/// Not handled yet: https://github.com/google/autocxx/issues/815.
10142/// Once this is handled, add equivalents of all the implicitly defaulted cases, at all
10143/// visibility levels.
10144/// applied to each of these:
10145/// * Default constructor
10146/// * Copy constructor
10147/// * Move constructor
10148/// in any of these:
10149/// * The class itself
10150/// * A base class
10151/// * A field of the class
10152/// * A field of a base class
10153/// with any of these access modifiers:
10154/// * private (impossible for implicitly defaulted)
10155/// * protected (impossible for implicitly defaulted)
10156/// * public
10157///
10158/// Various combinations of these lead to the default versions being deleted. The move and copy
10159/// ones also interact with each other in various ways.
10160///
10161/// TODO: Remove all the `int x` members after https://github.com/google/autocxx/issues/832 is
10162/// fixed.
10163fn test_implicit_constructor_rules() {
10164 let cxx = "";
10165 let hdr = indoc! {"
10166 struct AllImplicitlyDefaulted {
10167 void a() const {}
10168 };
10169
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070010170 struct AllExplicitlyDefaulted {
10171 AllExplicitlyDefaulted() = default;
10172 AllExplicitlyDefaulted(const AllExplicitlyDefaulted&) = default;
10173 AllExplicitlyDefaulted(AllExplicitlyDefaulted&&) = default;
10174 void a() const {};
10175 };
10176
Brian Silverman4e662aa2022-05-11 23:10:19 -070010177 struct PublicDeleted {
10178 PublicDeleted() = delete;
10179 PublicDeleted(const PublicDeleted&) = delete;
10180 PublicDeleted(PublicDeleted&&) = delete;
10181
10182 void a() const {}
10183
10184 int x;
10185 };
10186 struct PublicDeletedDefault {
10187 PublicDeletedDefault() = delete;
10188
10189 void a() const {}
10190
10191 int x;
10192 };
10193 struct PublicDeletedCopy {
10194 PublicDeletedCopy() = default;
10195 PublicDeletedCopy(const PublicDeletedCopy&) = delete;
10196
10197 void a() const {}
10198
10199 int x;
10200 };
10201 struct PublicDeletedCopyNoDefault {
10202 PublicDeletedCopyNoDefault(const PublicDeletedCopyNoDefault&) = delete;
10203
10204 void a() const {}
10205
10206 int x;
10207 };
10208 struct PublicMoveDeletedCopy {
10209 PublicMoveDeletedCopy() = default;
10210 PublicMoveDeletedCopy(const PublicMoveDeletedCopy&) = delete;
10211 PublicMoveDeletedCopy(PublicMoveDeletedCopy&&) = default;
10212
10213 void a() const {}
10214
10215 int x;
10216 };
10217 struct PublicDeletedMove {
10218 PublicDeletedMove() = default;
10219 PublicDeletedMove(PublicDeletedMove&&) = delete;
10220
10221 void a() const {}
10222
10223 int x;
10224 };
10225 struct PublicDeletedDestructor {
10226 PublicDeletedDestructor() = default;
10227 ~PublicDeletedDestructor() = delete;
10228
10229 void a() const {}
10230
10231 int x;
10232 };
10233 struct PublicDestructor {
10234 PublicDestructor() = default;
10235 ~PublicDestructor() = default;
10236
10237 void a() const {}
10238
10239 int x;
10240 };
10241
10242 struct ProtectedDeleted {
10243 void a() const {}
10244
10245 int x;
10246
10247 protected:
10248 ProtectedDeleted() = delete;
10249 ProtectedDeleted(const ProtectedDeleted&) = delete;
10250 ProtectedDeleted(ProtectedDeleted&&) = delete;
10251 };
10252 struct ProtectedDeletedDefault {
10253 void a() const {}
10254
10255 int x;
10256
10257 protected:
10258 ProtectedDeletedDefault() = delete;
10259 };
10260 struct ProtectedDeletedCopy {
10261 ProtectedDeletedCopy() = default;
10262
10263 void a() const {}
10264
10265 int x;
10266
10267 protected:
10268 ProtectedDeletedCopy(const ProtectedDeletedCopy&) = delete;
10269 };
10270 struct ProtectedDeletedCopyNoDefault {
10271 void a() const {}
10272
10273 int x;
10274
10275 protected:
10276 ProtectedDeletedCopyNoDefault(const ProtectedDeletedCopyNoDefault&) = delete;
10277 };
10278 struct ProtectedMoveDeletedCopy {
10279 ProtectedMoveDeletedCopy() = default;
10280
10281 void a() const {}
10282
10283 int x;
10284
10285 protected:
10286 ProtectedMoveDeletedCopy(const ProtectedMoveDeletedCopy&) = delete;
10287 ProtectedMoveDeletedCopy(ProtectedMoveDeletedCopy&&) = default;
10288 };
10289 struct ProtectedDeletedMove {
10290 ProtectedDeletedMove() = default;
10291
10292 void a() const {}
10293
10294 int x;
10295
10296 protected:
10297 ProtectedDeletedMove(ProtectedDeletedMove&&) = delete;
10298 };
10299 struct ProtectedDeletedDestructor {
10300 ProtectedDeletedDestructor() = default;
10301
10302 void a() const {}
10303
10304 int x;
10305
10306 protected:
10307 ~ProtectedDeletedDestructor() = delete;
10308 };
10309 struct ProtectedDestructor {
10310 ProtectedDestructor() = default;
10311
10312 void a() const {}
10313
10314 int x;
10315
10316 protected:
10317 ~ProtectedDestructor() = default;
10318 };
10319
10320 struct PrivateDeleted {
10321 void a() const {}
10322
10323 int x;
10324
10325 private:
10326 PrivateDeleted() = delete;
10327 PrivateDeleted(const PrivateDeleted&) = delete;
10328 PrivateDeleted(PrivateDeleted&&) = delete;
10329 };
10330 struct PrivateDeletedDefault {
10331 void a() const {}
10332
10333 int x;
10334
10335 private:
10336 PrivateDeletedDefault() = delete;
10337 };
10338 struct PrivateDeletedCopy {
10339 PrivateDeletedCopy() = default;
10340
10341 void a() const {}
10342
10343 int x;
10344
10345 private:
10346 PrivateDeletedCopy(const PrivateDeletedCopy&) = delete;
10347 };
10348 struct PrivateDeletedCopyNoDefault {
10349 void a() const {}
10350
10351 int x;
10352
10353 private:
10354 PrivateDeletedCopyNoDefault(const PrivateDeletedCopyNoDefault&) = delete;
10355 };
10356 struct PrivateMoveDeletedCopy {
10357 PrivateMoveDeletedCopy() = default;
10358
10359 void a() const {}
10360
10361 int x;
10362
10363 private:
10364 PrivateMoveDeletedCopy(const PrivateMoveDeletedCopy&) = delete;
10365 PrivateMoveDeletedCopy(PrivateMoveDeletedCopy&&) = default;
10366 };
10367 struct PrivateDeletedMove {
10368 PrivateDeletedMove() = default;
10369
10370 void a() const {}
10371
10372 int x;
10373
10374 private:
10375 PrivateDeletedMove(PrivateDeletedMove&&) = delete;
10376 };
10377 struct PrivateDeletedDestructor {
10378 PrivateDeletedDestructor() = default;
10379
10380 void a() const {}
10381
10382 int x;
10383
10384 private:
10385 ~PrivateDeletedDestructor() = delete;
10386 };
10387 struct PrivateDestructor {
10388 PrivateDestructor() = default;
10389
10390 void a() const {}
10391
10392 int x;
10393
10394 private:
10395 ~PrivateDestructor() = default;
10396 };
10397
10398 struct NonConstCopy {
10399 NonConstCopy() = default;
10400
10401 NonConstCopy(NonConstCopy&) {}
10402 NonConstCopy(NonConstCopy&&) = default;
10403
10404 void a() const {}
10405 };
10406 struct TwoCopy {
10407 TwoCopy() = default;
10408
10409 TwoCopy(TwoCopy&) {}
10410 TwoCopy(const TwoCopy&) {}
10411 TwoCopy(TwoCopy&&) = default;
10412
10413 void a() const {}
10414 };
10415
10416 struct MemberPointerDeleted {
10417 PublicDeleted *x;
10418
10419 void a() const {}
10420 };
10421
10422 struct MemberConstPointerDeleted {
10423 PublicDeleted *const x;
10424
10425 void a() const {}
10426 };
10427
10428 struct MemberConst {
10429 const int x;
10430
10431 void a() const {}
10432 };
10433
10434 struct MemberReferenceDeleted {
10435 PublicDeleted &x;
10436
10437 void a() const {}
10438 };
10439
10440 struct MemberConstReferenceDeleted {
10441 const PublicDeleted &x;
10442
10443 void a() const {}
10444 };
10445
10446 struct MemberReference {
10447 int &x;
10448
10449 void a() const {}
10450 };
10451
10452 struct MemberConstReference {
10453 const int &x;
10454
10455 void a() const {}
10456 };
10457
10458 struct MemberRvalueReferenceDeleted {
10459 PublicDeleted &&x;
10460
10461 void a() const {}
10462 };
10463
10464 struct MemberRvalueReference {
10465 int &&x;
10466
10467 void a() const {}
10468 };
10469
10470 struct BasePublicDeleted : public PublicDeleted {};
10471 struct BasePublicDeletedDefault : public PublicDeletedDefault {};
10472 struct BasePublicDeletedCopy : public PublicDeletedCopy {};
10473 struct BasePublicDeletedCopyNoDefault : public PublicDeletedCopyNoDefault { };
10474 struct BasePublicMoveDeletedCopy : public PublicMoveDeletedCopy {};
10475 struct BasePublicDeletedMove : public PublicDeletedMove {};
10476 struct BasePublicDeletedDestructor : public PublicDeletedDestructor {};
10477 struct BasePublicDestructor : public PublicDestructor {};
10478
10479 struct MemberPublicDeleted {
10480 void a() const {}
10481
10482 PublicDeleted member;
10483 };
10484 struct MemberPublicDeletedDefault {
10485 void a() const {}
10486
10487 PublicDeletedDefault member;
10488 };
10489 struct MemberPublicDeletedCopy {
10490 void a() const {}
10491
10492 PublicDeletedCopy member;
10493 };
10494 struct MemberPublicDeletedCopyNoDefault {
10495 void a() const {}
10496
10497 PublicDeletedCopyNoDefault member;
10498 };
10499 struct MemberPublicMoveDeletedCopy {
10500 void a() const {}
10501
10502 PublicMoveDeletedCopy member;
10503 };
10504 struct MemberPublicDeletedMove {
10505 void a() const {}
10506
10507 PublicDeletedMove member;
10508 };
10509 struct MemberPublicDeletedDestructor {
10510 void a() const {}
10511
10512 PublicDeletedDestructor member;
10513 };
10514 struct MemberPublicDestructor {
10515 void a() const {}
10516
10517 PublicDestructor member;
10518 };
10519
10520 struct BaseMemberPublicDeleted : public MemberPublicDeleted {};
10521 struct BaseMemberPublicDeletedDefault : public MemberPublicDeletedDefault {};
10522 struct BaseMemberPublicDeletedCopy : public MemberPublicDeletedCopy {};
10523 struct BaseMemberPublicDeletedCopyNoDefault : public MemberPublicDeletedCopyNoDefault {};
10524 struct BaseMemberPublicMoveDeletedCopy : public MemberPublicMoveDeletedCopy {};
10525 struct BaseMemberPublicDeletedMove : public MemberPublicDeletedMove {};
10526 struct BaseMemberPublicDeletedDestructor : public MemberPublicDeletedDestructor {};
10527 struct BaseMemberPublicDestructor : public MemberPublicDestructor {};
10528
10529 struct BaseProtectedDeleted : public ProtectedDeleted {};
10530 struct BaseProtectedDeletedDefault : public ProtectedDeletedDefault {};
10531 struct BaseProtectedDeletedCopy : public ProtectedDeletedCopy {};
10532 struct BaseProtectedDeletedCopyNoDefault : public ProtectedDeletedCopyNoDefault {};
10533 struct BaseProtectedMoveDeletedCopy : public ProtectedMoveDeletedCopy {};
10534 struct BaseProtectedDeletedMove : public ProtectedDeletedMove {};
10535 struct BaseProtectedDeletedDestructor : public ProtectedDeletedDestructor {};
10536 struct BaseProtectedDestructor : public ProtectedDestructor {};
10537
10538 struct MemberProtectedDeleted {
10539 void a() const {}
10540
10541 ProtectedDeleted member;
10542 };
10543 struct MemberProtectedDeletedDefault {
10544 void a() const {}
10545
10546 ProtectedDeletedDefault member;
10547 };
10548 struct MemberProtectedDeletedCopy {
10549 void a() const {}
10550
10551 ProtectedDeletedCopy member;
10552 };
10553 struct MemberProtectedDeletedCopyNoDefault {
10554 void a() const {}
10555
10556 ProtectedDeletedCopyNoDefault member;
10557 };
10558 struct MemberProtectedMoveDeletedCopy {
10559 void a() const {}
10560
10561 ProtectedMoveDeletedCopy member;
10562 };
10563 struct MemberProtectedDeletedMove {
10564 void a() const {}
10565
10566 ProtectedDeletedMove member;
10567 };
10568 struct MemberProtectedDeletedDestructor {
10569 void a() const {}
10570
10571 ProtectedDeletedDestructor member;
10572 };
10573 struct MemberProtectedDestructor {
10574 void a() const {}
10575
10576 ProtectedDestructor member;
10577 };
10578
10579 struct BaseMemberProtectedDeleted : public MemberProtectedDeleted {};
10580 struct BaseMemberProtectedDeletedDefault : public MemberProtectedDeletedDefault {};
10581 struct BaseMemberProtectedDeletedCopy : public MemberProtectedDeletedCopy {};
10582 struct BaseMemberProtectedDeletedCopyNoDefault : public MemberProtectedDeletedCopyNoDefault {};
10583 struct BaseMemberProtectedMoveDeletedCopy : public MemberProtectedMoveDeletedCopy {};
10584 struct BaseMemberProtectedDeletedMove : public MemberProtectedDeletedMove {};
10585 struct BaseMemberProtectedDeletedDestructor : public MemberProtectedDeletedDestructor {};
10586 struct BaseMemberProtectedDestructor : public MemberProtectedDestructor {};
10587
10588 struct BasePrivateDeleted : public PrivateDeleted {};
10589 struct BasePrivateDeletedDefault : public PrivateDeletedDefault {};
10590 struct BasePrivateDeletedCopy : public PrivateDeletedCopy {};
10591 struct BasePrivateDeletedCopyNoDefault : public PrivateDeletedCopyNoDefault {};
10592 struct BasePrivateMoveDeletedCopy : public PrivateMoveDeletedCopy {};
10593 struct BasePrivateDeletedMove : public PrivateDeletedMove {};
10594 struct BasePrivateDeletedDestructor : public PrivateDeletedDestructor {};
10595 struct BasePrivateDestructor : public PrivateDestructor {};
10596
10597 struct MemberPrivateDeleted {
10598 void a() const {}
10599
10600 PrivateDeleted member;
10601 };
10602 struct MemberPrivateDeletedDefault {
10603 void a() const {}
10604
10605 PrivateDeletedDefault member;
10606 };
10607 struct MemberPrivateDeletedCopy {
10608 void a() const {}
10609
10610 PrivateDeletedCopy member;
10611 };
10612 struct MemberPrivateDeletedCopyNoDefault {
10613 void a() const {}
10614
10615 PrivateDeletedCopyNoDefault member;
10616 };
10617 struct MemberPrivateMoveDeletedCopy {
10618 void a() const {}
10619
10620 PrivateMoveDeletedCopy member;
10621 };
10622 struct MemberPrivateDeletedMove {
10623 void a() const {}
10624
10625 PrivateDeletedMove member;
10626 };
10627 struct MemberPrivateDeletedDestructor {
10628 void a() const {}
10629
10630 PrivateDeletedDestructor member;
10631 };
10632 struct MemberPrivateDestructor {
10633 void a() const {}
10634
10635 PrivateDestructor member;
10636 };
10637
10638 struct BaseMemberPrivateDeleted : public MemberPrivateDeleted {};
10639 struct BaseMemberPrivateDeletedDefault : public MemberPrivateDeletedDefault {};
10640 struct BaseMemberPrivateDeletedCopy : public MemberPrivateDeletedCopy {};
10641 struct BaseMemberPrivateDeletedCopyNoDefault : public MemberPrivateDeletedCopyNoDefault {};
10642 struct BaseMemberPrivateMoveDeletedCopy : public MemberPrivateMoveDeletedCopy {};
10643 struct BaseMemberPrivateDeletedMove : public MemberPrivateDeletedMove {};
10644 struct BaseMemberPrivateDeletedDestructor : public MemberPrivateDeletedDestructor {};
10645 struct BaseMemberPrivateDestructor : public MemberPrivateDestructor {};
10646 "};
10647 let rs = quote! {
10648 // Some macros to test various operations on our types. Note that some of them define
10649 // functions which take arguments that the APIs defined in this test have no way to
10650 // produce, because we have C++ types which can't be constructed (for example). In a real
10651 // program, there might be other C++ APIs which can instantiate these types.
10652
10653 // TODO: https://github.com/google/autocxx/issues/829: Should this be merged with
10654 // `test_make_unique`? Currently types where the Rust wrappers permit this but not that
10655 // aren't running C++ destructors.
10656 macro_rules! test_constructible {
10657 [$t:ty] => {
10658 moveit! {
10659 let _moveit_t = <$t>::new();
10660 }
10661 }
10662 }
10663 macro_rules! test_make_unique {
10664 [$t:ty] => {
10665 let _unique_t = <$t>::new().within_unique_ptr();
10666 }
10667 }
10668 macro_rules! test_copyable {
10669 [$t:ty] => {
10670 {
10671 fn test_copyable(moveit_t: impl autocxx::moveit::new::New<Output = $t>) {
10672 moveit! {
10673 let moveit_t = moveit_t;
10674 let _copied_t = autocxx::moveit::new::copy(moveit_t);
10675 }
10676 }
10677 }
10678 }
10679 }
10680 macro_rules! test_movable {
10681 [$t:ty] => {
10682 {
10683 fn test_movable(moveit_t: impl autocxx::moveit::new::New<Output = $t>) {
10684 moveit! {
10685 let moveit_t = moveit_t;
10686 let _moved_t = autocxx::moveit::new::mov(moveit_t);
10687 }
10688 }
10689 }
10690 }
10691 }
10692 macro_rules! test_call_a {
10693 [$t:ty] => {
10694 {
10695 fn test_call_a(t: &$t) {
10696 t.a();
10697 }
10698 }
10699 }
10700 }
10701 macro_rules! test_call_a_as {
10702 [$t:ty, $parent:ty] => {
10703 {
10704 fn test_call_a(t: &$t) {
10705 let t: &$parent = t.as_ref();
10706 t.a();
10707 }
10708 }
10709 }
10710 }
10711
10712 test_constructible![ffi::AllImplicitlyDefaulted];
10713 test_make_unique![ffi::AllImplicitlyDefaulted];
10714 test_copyable![ffi::AllImplicitlyDefaulted];
10715 test_movable![ffi::AllImplicitlyDefaulted];
10716 test_call_a![ffi::AllImplicitlyDefaulted];
10717
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070010718 test_constructible![ffi::AllExplicitlyDefaulted];
10719 test_make_unique![ffi::AllExplicitlyDefaulted];
10720 test_copyable![ffi::AllExplicitlyDefaulted];
10721 test_movable![ffi::AllExplicitlyDefaulted];
10722 test_call_a![ffi::AllExplicitlyDefaulted];
10723
Brian Silverman4e662aa2022-05-11 23:10:19 -070010724 test_call_a![ffi::PublicDeleted];
10725
10726 test_copyable![ffi::PublicDeletedDefault];
10727 test_movable![ffi::PublicDeletedDefault];
10728 test_call_a![ffi::PublicDeletedDefault];
10729
10730 test_constructible![ffi::PublicDeletedCopy];
10731 test_make_unique![ffi::PublicDeletedCopy];
10732 test_call_a![ffi::PublicDeletedCopy];
10733
10734 test_call_a![ffi::PublicDeletedCopyNoDefault];
10735
10736 test_constructible![ffi::PublicMoveDeletedCopy];
10737 test_make_unique![ffi::PublicMoveDeletedCopy];
10738 test_movable![ffi::PublicMoveDeletedCopy];
10739 test_call_a![ffi::PublicMoveDeletedCopy];
10740
10741 test_constructible![ffi::PublicDeletedMove];
10742 test_make_unique![ffi::PublicDeletedMove];
10743 test_call_a![ffi::PublicDeletedMove];
10744
10745 test_constructible![ffi::PublicDeletedDestructor];
10746 test_copyable![ffi::PublicDeletedDestructor];
10747 test_call_a![ffi::PublicDeletedDestructor];
10748
10749 test_constructible![ffi::PublicDestructor];
10750 test_make_unique![ffi::PublicDestructor];
10751 test_copyable![ffi::PublicDestructor];
10752 test_call_a![ffi::PublicDestructor];
10753
10754 test_call_a![ffi::ProtectedDeleted];
10755
10756 test_copyable![ffi::ProtectedDeletedDefault];
10757 test_movable![ffi::ProtectedDeletedDefault];
10758 test_call_a![ffi::ProtectedDeletedDefault];
10759
10760 test_constructible![ffi::ProtectedDeletedCopy];
10761 test_make_unique![ffi::ProtectedDeletedCopy];
10762 test_call_a![ffi::ProtectedDeletedCopy];
10763
10764 test_call_a![ffi::ProtectedDeletedCopyNoDefault];
10765
10766 test_constructible![ffi::ProtectedMoveDeletedCopy];
10767 test_make_unique![ffi::ProtectedMoveDeletedCopy];
10768 test_call_a![ffi::ProtectedMoveDeletedCopy];
10769
10770 test_constructible![ffi::ProtectedDeletedMove];
10771 test_make_unique![ffi::ProtectedDeletedMove];
10772 test_call_a![ffi::ProtectedDeletedMove];
10773
10774 test_constructible![ffi::ProtectedDeletedDestructor];
10775 test_copyable![ffi::ProtectedDeletedDestructor];
10776 test_call_a![ffi::ProtectedDeletedDestructor];
10777
10778 test_constructible![ffi::ProtectedDestructor];
10779 test_copyable![ffi::ProtectedDestructor];
10780 test_call_a![ffi::ProtectedDestructor];
10781
10782 test_call_a![ffi::PrivateDeleted];
10783
10784 test_copyable![ffi::PrivateDeletedDefault];
10785 test_movable![ffi::PrivateDeletedDefault];
10786 test_call_a![ffi::PrivateDeletedDefault];
10787
10788 test_constructible![ffi::PrivateDeletedCopy];
10789 test_make_unique![ffi::PrivateDeletedCopy];
10790 test_call_a![ffi::PrivateDeletedCopy];
10791
10792 test_call_a![ffi::PrivateDeletedCopyNoDefault];
10793
10794 test_constructible![ffi::PrivateMoveDeletedCopy];
10795 test_make_unique![ffi::PrivateMoveDeletedCopy];
10796 test_call_a![ffi::PrivateMoveDeletedCopy];
10797
10798 test_constructible![ffi::PrivateDeletedMove];
10799 test_make_unique![ffi::PrivateDeletedMove];
10800 test_call_a![ffi::PrivateDeletedMove];
10801
10802 test_constructible![ffi::PrivateDeletedDestructor];
10803 test_copyable![ffi::PrivateDeletedDestructor];
10804 test_call_a![ffi::PrivateDeletedDestructor];
10805
10806 test_constructible![ffi::PrivateDestructor];
10807 test_copyable![ffi::PrivateDestructor];
10808 test_call_a![ffi::PrivateDestructor];
10809
10810 test_constructible![ffi::NonConstCopy];
10811 test_make_unique![ffi::NonConstCopy];
10812 test_movable![ffi::NonConstCopy];
10813 test_call_a![ffi::NonConstCopy];
10814
10815 test_constructible![ffi::TwoCopy];
10816 test_make_unique![ffi::TwoCopy];
10817 test_copyable![ffi::TwoCopy];
10818 test_movable![ffi::TwoCopy];
10819 test_call_a![ffi::TwoCopy];
10820
10821 // TODO: https://github.com/google/autocxx/issues/865
10822 // Treat pointers and references differently so this has a default constructor.
10823 //test_constructible![ffi::MemberPointerDeleted];
10824 //test_make_unique![ffi::MemberPointerDeleted];
10825 test_copyable![ffi::MemberPointerDeleted];
10826 test_movable![ffi::MemberPointerDeleted];
10827 test_call_a![ffi::MemberPointerDeleted];
10828
10829 test_copyable![ffi::MemberConstPointerDeleted];
10830 test_movable![ffi::MemberConstPointerDeleted];
10831 test_call_a![ffi::MemberConstPointerDeleted];
10832
10833 //test_copyable![ffi::MemberConst];
10834 //test_movable![ffi::MemberConst];
10835 //test_call_a![ffi::MemberConst];
10836
10837 test_copyable![ffi::MemberReferenceDeleted];
10838 test_movable![ffi::MemberReferenceDeleted];
10839 test_call_a![ffi::MemberReferenceDeleted];
10840
10841 test_copyable![ffi::MemberConstReferenceDeleted];
10842 test_movable![ffi::MemberConstReferenceDeleted];
10843 test_call_a![ffi::MemberConstReferenceDeleted];
10844
10845 test_copyable![ffi::MemberReference];
10846 test_movable![ffi::MemberReference];
10847 test_call_a![ffi::MemberReference];
10848
10849 test_copyable![ffi::MemberConstReference];
10850 test_movable![ffi::MemberConstReference];
10851 test_call_a![ffi::MemberConstReference];
10852
10853 test_movable![ffi::MemberRvalueReferenceDeleted];
10854 test_call_a![ffi::MemberRvalueReferenceDeleted];
10855
10856 test_movable![ffi::MemberRvalueReference];
10857 test_call_a![ffi::MemberRvalueReference];
10858
10859 test_call_a_as![ffi::BasePublicDeleted, ffi::PublicDeleted];
10860
10861 test_copyable![ffi::BasePublicDeletedDefault];
10862 test_movable![ffi::BasePublicDeletedDefault];
10863 test_call_a_as![ffi::BasePublicDeletedDefault, ffi::PublicDeletedDefault];
10864
10865 test_constructible![ffi::BasePublicDeletedCopy];
10866 test_make_unique![ffi::BasePublicDeletedCopy];
10867 test_call_a_as![ffi::BasePublicDeletedCopy, ffi::PublicDeletedCopy];
10868
10869 test_call_a_as![ffi::BasePublicDeletedCopyNoDefault, ffi::PublicDeletedCopyNoDefault];
10870
10871 test_constructible![ffi::BasePublicMoveDeletedCopy];
10872 test_make_unique![ffi::BasePublicMoveDeletedCopy];
10873 test_movable![ffi::BasePublicMoveDeletedCopy];
10874 test_call_a_as![ffi::BasePublicMoveDeletedCopy, ffi::PublicMoveDeletedCopy];
10875
10876 test_constructible![ffi::BasePublicDeletedMove];
10877 test_make_unique![ffi::BasePublicDeletedMove];
10878 test_call_a_as![ffi::BasePublicDeletedMove, ffi::PublicDeletedMove];
10879
10880 test_call_a_as![ffi::BasePublicDeletedDestructor, ffi::PublicDeletedDestructor];
10881
10882 test_constructible![ffi::BasePublicDestructor];
10883 test_make_unique![ffi::BasePublicDestructor];
10884 test_copyable![ffi::BasePublicDestructor];
10885 test_call_a_as![ffi::BasePublicDestructor, ffi::PublicDestructor];
10886
10887 test_call_a![ffi::MemberPublicDeleted];
10888
10889 test_copyable![ffi::MemberPublicDeletedDefault];
10890 test_movable![ffi::MemberPublicDeletedDefault];
10891 test_call_a![ffi::MemberPublicDeletedDefault];
10892
10893 test_constructible![ffi::MemberPublicDeletedCopy];
10894 test_make_unique![ffi::MemberPublicDeletedCopy];
10895 test_call_a![ffi::MemberPublicDeletedCopy];
10896
10897 test_call_a![ffi::MemberPublicDeletedCopyNoDefault];
10898
10899 test_constructible![ffi::MemberPublicMoveDeletedCopy];
10900 test_make_unique![ffi::MemberPublicMoveDeletedCopy];
10901 test_movable![ffi::MemberPublicMoveDeletedCopy];
10902 test_call_a![ffi::MemberPublicMoveDeletedCopy];
10903
10904 test_constructible![ffi::MemberPublicDeletedMove];
10905 test_make_unique![ffi::MemberPublicDeletedMove];
10906 test_call_a![ffi::MemberPublicDeletedMove];
10907
10908 test_call_a![ffi::MemberPublicDeletedDestructor];
10909
10910 test_constructible![ffi::MemberPublicDestructor];
10911 test_make_unique![ffi::MemberPublicDestructor];
10912 test_copyable![ffi::MemberPublicDestructor];
10913 test_call_a![ffi::MemberPublicDestructor];
10914
10915 test_call_a_as![ffi::BaseMemberPublicDeleted, ffi::MemberPublicDeleted];
10916
10917 test_copyable![ffi::BaseMemberPublicDeletedDefault];
10918 test_movable![ffi::BaseMemberPublicDeletedDefault];
10919 test_call_a_as![ffi::BaseMemberPublicDeletedDefault, ffi::MemberPublicDeletedDefault];
10920
10921 test_constructible![ffi::BaseMemberPublicDeletedCopy];
10922 test_make_unique![ffi::BaseMemberPublicDeletedCopy];
10923 test_call_a_as![ffi::BaseMemberPublicDeletedCopy, ffi::MemberPublicDeletedCopy];
10924
10925 test_call_a_as![ffi::BaseMemberPublicDeletedCopyNoDefault, ffi::MemberPublicDeletedCopyNoDefault];
10926
10927 test_constructible![ffi::BaseMemberPublicMoveDeletedCopy];
10928 test_make_unique![ffi::BaseMemberPublicMoveDeletedCopy];
10929 test_movable![ffi::BaseMemberPublicMoveDeletedCopy];
10930 test_call_a_as![ffi::BaseMemberPublicMoveDeletedCopy, ffi::MemberPublicMoveDeletedCopy];
10931
10932 test_constructible![ffi::BaseMemberPublicDeletedMove];
10933 test_make_unique![ffi::BaseMemberPublicDeletedMove];
10934 test_call_a_as![ffi::BaseMemberPublicDeletedMove, ffi::MemberPublicDeletedMove];
10935
10936 test_call_a_as![ffi::BaseMemberPublicDeletedDestructor, ffi::MemberPublicDeletedDestructor];
10937
10938 test_constructible![ffi::BaseMemberPublicDestructor];
10939 test_make_unique![ffi::BaseMemberPublicDestructor];
10940 test_copyable![ffi::BaseMemberPublicDestructor];
10941 test_call_a_as![ffi::BaseMemberPublicDestructor, ffi::MemberPublicDestructor];
10942
10943 test_call_a_as![ffi::BaseProtectedDeleted, ffi::ProtectedDeleted];
10944
10945 test_copyable![ffi::BaseProtectedDeletedDefault];
10946 test_movable![ffi::BaseProtectedDeletedDefault];
10947 test_call_a_as![ffi::BaseProtectedDeletedDefault, ffi::ProtectedDeletedDefault];
10948
10949 test_constructible![ffi::BaseProtectedDeletedCopy];
10950 test_make_unique![ffi::BaseProtectedDeletedCopy];
10951 test_call_a_as![ffi::BaseProtectedDeletedCopy, ffi::ProtectedDeletedCopy];
10952
10953 test_call_a_as![ffi::BaseProtectedDeletedCopyNoDefault, ffi::ProtectedDeletedCopyNoDefault];
10954
10955 test_constructible![ffi::BaseProtectedMoveDeletedCopy];
10956 test_make_unique![ffi::BaseProtectedMoveDeletedCopy];
10957 test_movable![ffi::BaseProtectedMoveDeletedCopy];
10958 test_call_a_as![ffi::BaseProtectedMoveDeletedCopy, ffi::ProtectedMoveDeletedCopy];
10959
10960 test_constructible![ffi::BaseProtectedDeletedMove];
10961 test_make_unique![ffi::BaseProtectedDeletedMove];
10962 test_call_a_as![ffi::BaseProtectedDeletedMove, ffi::ProtectedDeletedMove];
10963
10964 test_call_a_as![ffi::BaseProtectedDeletedDestructor, ffi::ProtectedDeletedDestructor];
10965
10966 test_constructible![ffi::BaseProtectedDestructor];
10967 test_make_unique![ffi::BaseProtectedDestructor];
10968 test_copyable![ffi::BaseProtectedDestructor];
10969 test_call_a_as![ffi::BaseProtectedDestructor, ffi::ProtectedDestructor];
10970
10971 test_call_a![ffi::MemberProtectedDeleted];
10972
10973 test_copyable![ffi::MemberProtectedDeletedDefault];
10974 test_movable![ffi::MemberProtectedDeletedDefault];
10975 test_call_a![ffi::MemberProtectedDeletedDefault];
10976
10977 test_constructible![ffi::MemberProtectedDeletedCopy];
10978 test_make_unique![ffi::MemberProtectedDeletedCopy];
10979 test_call_a![ffi::MemberProtectedDeletedCopy];
10980
10981 test_call_a![ffi::MemberProtectedDeletedCopyNoDefault];
10982
10983 test_constructible![ffi::MemberProtectedMoveDeletedCopy];
10984 test_make_unique![ffi::MemberProtectedMoveDeletedCopy];
10985 test_call_a![ffi::MemberProtectedMoveDeletedCopy];
10986
10987 test_constructible![ffi::MemberProtectedDeletedMove];
10988 test_make_unique![ffi::MemberProtectedDeletedMove];
10989 test_call_a![ffi::MemberProtectedDeletedMove];
10990
10991 test_call_a![ffi::MemberProtectedDeletedDestructor];
10992
10993 test_call_a![ffi::MemberProtectedDestructor];
10994
10995 test_call_a_as![ffi::BaseMemberProtectedDeleted, ffi::MemberProtectedDeleted];
10996
10997 test_copyable![ffi::BaseMemberProtectedDeletedDefault];
10998 test_movable![ffi::BaseMemberProtectedDeletedDefault];
10999 test_call_a_as![ffi::BaseMemberProtectedDeletedDefault, ffi::MemberProtectedDeletedDefault];
11000
11001 test_constructible![ffi::BaseMemberProtectedDeletedCopy];
11002 test_make_unique![ffi::BaseMemberProtectedDeletedCopy];
11003 test_call_a_as![ffi::BaseMemberProtectedDeletedCopy, ffi::MemberProtectedDeletedCopy];
11004
11005 test_call_a_as![ffi::BaseMemberProtectedDeletedCopyNoDefault, ffi::MemberProtectedDeletedCopyNoDefault];
11006
11007 test_constructible![ffi::BaseMemberProtectedMoveDeletedCopy];
11008 test_make_unique![ffi::BaseMemberProtectedMoveDeletedCopy];
11009 test_call_a_as![ffi::BaseMemberProtectedMoveDeletedCopy, ffi::MemberProtectedMoveDeletedCopy];
11010
11011 test_constructible![ffi::BaseMemberProtectedDeletedMove];
11012 test_make_unique![ffi::BaseMemberProtectedDeletedMove];
11013 test_call_a_as![ffi::BaseMemberProtectedDeletedMove, ffi::MemberProtectedDeletedMove];
11014
11015 test_call_a_as![ffi::BaseMemberProtectedDeletedDestructor, ffi::MemberProtectedDeletedDestructor];
11016
11017 test_call_a_as![ffi::BaseMemberProtectedDestructor, ffi::MemberProtectedDestructor];
11018
11019 test_call_a_as![ffi::BasePrivateDeleted, ffi::PrivateDeleted];
11020
11021 test_copyable![ffi::BasePrivateDeletedDefault];
11022 test_movable![ffi::BasePrivateDeletedDefault];
11023 test_call_a_as![ffi::BasePrivateDeletedDefault, ffi::PrivateDeletedDefault];
11024
11025 test_constructible![ffi::BasePrivateDeletedCopy];
11026 test_make_unique![ffi::BasePrivateDeletedCopy];
11027 test_call_a_as![ffi::BasePrivateDeletedCopy, ffi::PrivateDeletedCopy];
11028
11029 test_call_a_as![ffi::BasePrivateDeletedCopyNoDefault, ffi::PrivateDeletedCopyNoDefault];
11030
11031 test_constructible![ffi::BasePrivateMoveDeletedCopy];
11032 test_make_unique![ffi::BasePrivateMoveDeletedCopy];
11033 test_call_a_as![ffi::BasePrivateMoveDeletedCopy, ffi::PrivateMoveDeletedCopy];
11034
11035 test_constructible![ffi::BasePrivateDeletedMove];
11036 test_make_unique![ffi::BasePrivateDeletedMove];
11037 test_call_a_as![ffi::BasePrivateDeletedMove, ffi::PrivateDeletedMove];
11038
11039 test_call_a_as![ffi::BasePrivateDeletedDestructor, ffi::PrivateDeletedDestructor];
11040
11041 test_call_a_as![ffi::BasePrivateDestructor, ffi::PrivateDestructor];
11042
11043 test_call_a![ffi::MemberPrivateDeleted];
11044
11045 test_copyable![ffi::MemberPrivateDeletedDefault];
11046 test_movable![ffi::MemberPrivateDeletedDefault];
11047 test_call_a![ffi::MemberPrivateDeletedDefault];
11048
11049 test_constructible![ffi::MemberPrivateDeletedCopy];
11050 test_make_unique![ffi::MemberPrivateDeletedCopy];
11051 test_call_a![ffi::MemberPrivateDeletedCopy];
11052
11053 test_call_a![ffi::MemberPrivateDeletedCopyNoDefault];
11054
11055 test_constructible![ffi::MemberPrivateMoveDeletedCopy];
11056 test_make_unique![ffi::MemberPrivateMoveDeletedCopy];
11057 test_call_a![ffi::MemberPrivateMoveDeletedCopy];
11058
11059 test_constructible![ffi::MemberPrivateDeletedMove];
11060 test_make_unique![ffi::MemberPrivateDeletedMove];
11061 test_call_a![ffi::MemberPrivateDeletedMove];
11062
11063 test_call_a![ffi::MemberPrivateDeletedDestructor];
11064
11065 test_call_a![ffi::MemberPrivateDestructor];
11066
11067 test_call_a_as![ffi::BaseMemberPrivateDeleted, ffi::MemberPrivateDeleted];
11068
11069 test_copyable![ffi::BaseMemberPrivateDeletedDefault];
11070 test_movable![ffi::BaseMemberPrivateDeletedDefault];
11071 test_call_a_as![ffi::BaseMemberPrivateDeletedDefault, ffi::MemberPrivateDeletedDefault];
11072
11073 test_constructible![ffi::BaseMemberPrivateDeletedCopy];
11074 test_make_unique![ffi::BaseMemberPrivateDeletedCopy];
11075 test_call_a_as![ffi::BaseMemberPrivateDeletedCopy, ffi::MemberPrivateDeletedCopy];
11076
11077 test_call_a_as![ffi::BaseMemberPrivateDeletedCopyNoDefault, ffi::MemberPrivateDeletedCopyNoDefault];
11078
11079 test_constructible![ffi::BaseMemberPrivateMoveDeletedCopy];
11080 test_make_unique![ffi::BaseMemberPrivateMoveDeletedCopy];
11081 test_call_a_as![ffi::BaseMemberPrivateMoveDeletedCopy, ffi::MemberPrivateMoveDeletedCopy];
11082
11083 test_constructible![ffi::BaseMemberPrivateDeletedMove];
11084 test_make_unique![ffi::BaseMemberPrivateDeletedMove];
11085 test_call_a_as![ffi::BaseMemberPrivateDeletedMove, ffi::MemberPrivateDeletedMove];
11086
11087 test_call_a_as![ffi::BaseMemberPrivateDeletedDestructor, ffi::MemberPrivateDeletedDestructor];
11088
11089 test_call_a_as![ffi::BaseMemberPrivateDestructor, ffi::MemberPrivateDestructor];
11090 };
11091 run_test(
11092 cxx,
11093 hdr,
11094 rs,
11095 &[
11096 "AllImplicitlyDefaulted",
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070011097 "AllExplicitlyDefaulted",
Brian Silverman4e662aa2022-05-11 23:10:19 -070011098 "PublicDeleted",
11099 "PublicDeletedDefault",
11100 "PublicDeletedCopy",
11101 "PublicDeletedCopyNoDefault",
11102 "PublicMoveDeletedCopy",
11103 "PublicDeletedMove",
11104 "PublicDeletedDestructor",
11105 "PublicDestructor",
11106 "ProtectedDeleted",
11107 "ProtectedDeletedDefault",
11108 "ProtectedDeletedCopy",
11109 "ProtectedDeletedCopyNoDefault",
11110 "ProtectedMoveDeletedCopy",
11111 "ProtectedDeletedMove",
11112 "ProtectedDeletedDestructor",
11113 "ProtectedDestructor",
11114 "PrivateDeleted",
11115 "PrivateDeletedDefault",
11116 "PrivateDeletedCopy",
11117 "PrivateDeletedCopyNoDefault",
11118 "PrivateMoveDeletedCopy",
11119 "PrivateDeletedMove",
11120 "PrivateDeletedDestructor",
11121 "PrivateDestructor",
11122 "NonConstCopy",
11123 "TwoCopy",
11124 "MemberPointerDeleted",
11125 "MemberConstPointerDeleted",
11126 // TODO: Handle top-level const on C++ members correctly.
11127 //"MemberConst",
11128 "MemberReferenceDeleted",
11129 "MemberConstReferenceDeleted",
11130 "MemberReference",
11131 "MemberConstReference",
11132 "MemberRvalueReferenceDeleted",
11133 "MemberRvalueReference",
11134 "BasePublicDeleted",
11135 "BasePublicDeletedDefault",
11136 "BasePublicDeletedCopy",
11137 "BasePublicDeletedCopyNoDefault",
11138 "BasePublicMoveDeletedCopy",
11139 "BasePublicDeletedMove",
11140 "BasePublicDeletedDestructor",
11141 "BasePublicDestructor",
11142 "MemberPublicDeleted",
11143 "MemberPublicDeletedDefault",
11144 "MemberPublicDeletedCopy",
11145 "MemberPublicDeletedCopyNoDefault",
11146 "MemberPublicMoveDeletedCopy",
11147 "MemberPublicDeletedMove",
11148 "MemberPublicDeletedDestructor",
11149 "MemberPublicDestructor",
11150 "BaseMemberPublicDeleted",
11151 "BaseMemberPublicDeletedDefault",
11152 "BaseMemberPublicDeletedCopy",
11153 "BaseMemberPublicDeletedCopyNoDefault",
11154 "BaseMemberPublicMoveDeletedCopy",
11155 "BaseMemberPublicDeletedMove",
11156 "BaseMemberPublicDeletedDestructor",
11157 "BaseMemberPublicDestructor",
11158 "BaseProtectedDeleted",
11159 "BaseProtectedDeletedDefault",
11160 "BaseProtectedDeletedCopy",
11161 "BaseProtectedDeletedCopyNoDefault",
11162 "BaseProtectedMoveDeletedCopy",
11163 "BaseProtectedDeletedMove",
11164 "BaseProtectedDeletedDestructor",
11165 "BaseProtectedDestructor",
11166 "MemberProtectedDeleted",
11167 "MemberProtectedDeletedDefault",
11168 "MemberProtectedDeletedCopy",
11169 "MemberProtectedDeletedCopyNoDefault",
11170 "MemberProtectedMoveDeletedCopy",
11171 "MemberProtectedDeletedMove",
11172 "MemberProtectedDeletedDestructor",
11173 "MemberProtectedDestructor",
11174 "BaseMemberProtectedDeleted",
11175 "BaseMemberProtectedDeletedDefault",
11176 "BaseMemberProtectedDeletedCopy",
11177 "BaseMemberProtectedDeletedCopyNoDefault",
11178 "BaseMemberProtectedMoveDeletedCopy",
11179 "BaseMemberProtectedDeletedMove",
11180 "BaseMemberProtectedDeletedDestructor",
11181 "BaseMemberProtectedDestructor",
11182 "BasePrivateDeleted",
11183 "BasePrivateDeletedDefault",
11184 "BasePrivateDeletedCopy",
11185 "BasePrivateDeletedCopyNoDefault",
11186 "BasePrivateMoveDeletedCopy",
11187 "BasePrivateDeletedMove",
11188 "BasePrivateDeletedDestructor",
11189 "BasePrivateDestructor",
11190 "MemberPrivateDeleted",
11191 "MemberPrivateDeletedDefault",
11192 "MemberPrivateDeletedCopy",
11193 "MemberPrivateDeletedCopyNoDefault",
11194 "MemberPrivateMoveDeletedCopy",
11195 "MemberPrivateDeletedMove",
11196 "MemberPrivateDeletedDestructor",
11197 "MemberPrivateDestructor",
11198 "BaseMemberPrivateDeleted",
11199 "BaseMemberPrivateDeletedDefault",
11200 "BaseMemberPrivateDeletedCopy",
11201 "BaseMemberPrivateDeletedCopyNoDefault",
11202 "BaseMemberPrivateMoveDeletedCopy",
11203 "BaseMemberPrivateDeletedMove",
11204 "BaseMemberPrivateDeletedDestructor",
11205 "BaseMemberPrivateDestructor",
11206 ],
11207 &[],
11208 );
11209}
11210
11211#[test]
11212/// Test that destructors hidden in various places are correctly called.
11213///
11214/// Some types are excluded because we know they behave poorly due to
11215/// https://github.com/google/autocxx/issues/829.
11216fn test_tricky_destructors() {
11217 let cxx = "";
11218 let hdr = indoc! {"
11219 #include <stdio.h>
11220 #include <stdlib.h>
11221 // A simple type to let Rust verify the destructor is run.
11222 struct DestructorFlag {
11223 DestructorFlag() = default;
11224 DestructorFlag(const DestructorFlag&) = default;
11225 DestructorFlag(DestructorFlag&&) = default;
11226
11227 ~DestructorFlag() {
11228 if (!flag) return;
11229 if (*flag) {
11230 fprintf(stderr, \"DestructorFlag is already set\\n\");
11231 abort();
11232 }
11233 *flag = true;
11234 // Note we deliberately do NOT clear the value of `flag`, to catch Rust calling
11235 // this destructor twice.
11236 }
11237
11238 bool *flag = nullptr;
11239 };
11240
11241 struct ImplicitlyDefaulted {
11242 DestructorFlag flag;
11243
11244 void set_flag(bool *flag_pointer) { flag.flag = flag_pointer; }
11245 };
11246 struct ExplicitlyDefaulted {
11247 ExplicitlyDefaulted() = default;
11248 ~ExplicitlyDefaulted() = default;
11249
11250 DestructorFlag flag;
11251
11252 void set_flag(bool *flag_pointer) { flag.flag = flag_pointer; }
11253 };
11254 struct Explicit {
11255 Explicit() = default;
11256 ~Explicit() {}
11257
11258 DestructorFlag flag;
11259
11260 void set_flag(bool *flag_pointer) { flag.flag = flag_pointer; }
11261 };
11262
11263 struct BaseImplicitlyDefaulted : public ImplicitlyDefaulted {
11264 void set_flag(bool *flag_pointer) { ImplicitlyDefaulted::set_flag(flag_pointer); }
11265 };
11266 struct BaseExplicitlyDefaulted : public ExplicitlyDefaulted {
11267 void set_flag(bool *flag_pointer) { ExplicitlyDefaulted::set_flag(flag_pointer); }
11268 };
11269 struct BaseExplicit : public Explicit {
11270 void set_flag(bool *flag_pointer) { Explicit::set_flag(flag_pointer); }
11271 };
11272
11273 struct MemberImplicitlyDefaulted {
11274 ImplicitlyDefaulted member;
11275
11276 void set_flag(bool *flag_pointer) { member.set_flag(flag_pointer); }
11277 };
11278 struct MemberExplicitlyDefaulted {
11279 ExplicitlyDefaulted member;
11280
11281 void set_flag(bool *flag_pointer) { member.set_flag(flag_pointer); }
11282 };
11283 struct MemberExplicit {
11284 Explicit member;
11285
11286 void set_flag(bool *flag_pointer) { member.set_flag(flag_pointer); }
11287 };
11288
11289 struct BaseMemberImplicitlyDefaulted : public MemberImplicitlyDefaulted {
11290 void set_flag(bool *flag_pointer) { MemberImplicitlyDefaulted::set_flag(flag_pointer); }
11291 };
11292 struct BaseMemberExplicitlyDefaulted : public MemberExplicitlyDefaulted {
11293 void set_flag(bool *flag_pointer) { MemberExplicitlyDefaulted::set_flag(flag_pointer); }
11294 };
11295 struct BaseMemberExplicit : public MemberExplicit {
11296 void set_flag(bool *flag_pointer) { MemberExplicit::set_flag(flag_pointer); }
11297 };
11298 "};
11299 let rs = quote! {
11300 macro_rules! test_type {
11301 [$t:ty] => {
11302 let mut unique_t = <$t>::new().within_unique_ptr();
11303 let mut destructor_flag = false;
11304 unsafe {
11305 unique_t.pin_mut().set_flag(&mut destructor_flag);
11306 }
11307 std::mem::drop(unique_t);
11308 assert!(destructor_flag, "Destructor did not run with make_unique for {}", quote::quote!{$t});
11309
11310 moveit! {
11311 let mut moveit_t = <$t>::new();
11312 }
11313 let mut destructor_flag = false;
11314 unsafe {
11315 moveit_t.as_mut().set_flag(&mut destructor_flag);
11316 }
11317 std::mem::drop(moveit_t);
11318 assert!(destructor_flag, "Destructor did not run with moveit for {}", quote::quote!{$t});
11319 }
11320 }
11321
11322 test_type![ffi::ImplicitlyDefaulted];
11323 test_type![ffi::ExplicitlyDefaulted];
11324 test_type![ffi::Explicit];
11325 test_type![ffi::BaseImplicitlyDefaulted];
11326 test_type![ffi::BaseExplicitlyDefaulted];
11327 test_type![ffi::BaseExplicit];
11328 test_type![ffi::MemberImplicitlyDefaulted];
11329 test_type![ffi::MemberExplicitlyDefaulted];
11330 test_type![ffi::MemberExplicit];
11331 test_type![ffi::BaseMemberImplicitlyDefaulted];
11332 test_type![ffi::BaseMemberExplicitlyDefaulted];
11333 test_type![ffi::BaseMemberExplicit];
11334 };
11335 run_test(
11336 cxx,
11337 hdr,
11338 rs,
11339 &[
11340 "DestructorFlag",
11341 "ImplicitlyDefaulted",
11342 "ExplicitlyDefaulted",
11343 "Explicit",
11344 "BaseImplicitlyDefaulted",
11345 "BaseExplicitlyDefaulted",
11346 "BaseExplicit",
11347 "MemberImplicitlyDefaulted",
11348 "MemberExplicitlyDefaulted",
11349 "MemberExplicit",
11350 "BaseMemberImplicitlyDefaulted",
11351 "BaseMemberExplicitlyDefaulted",
11352 "BaseMemberExplicit",
11353 ],
11354 &[],
11355 );
11356}
11357
11358#[test]
11359fn test_concretize() {
11360 let hdr = indoc! {"
11361 #include <string>
11362 template<typename CONTENTS>
11363 class Container {
11364 private:
11365 CONTENTS* contents;
11366 };
11367 struct B {
11368 std::string a;
11369 };
11370 "};
11371 run_test_ex(
11372 "",
11373 hdr,
11374 quote! {},
11375 quote! {
11376 concrete!("Container<B>", ContainerOfB)
11377 generate!("B")
11378 },
11379 None,
11380 None,
11381 Some(quote! {
11382 struct HasAField {
11383 contents: ffi::ContainerOfB
11384 }
11385 }),
11386 );
11387}
11388
11389#[test]
11390fn test_doc_comments_survive() {
11391 let hdr = indoc! {"
11392 #include <cstdint>
11393 /// Struct line A
11394 /// Struct line B
11395 struct A { int b; };
11396
11397 /// POD struct line A
11398 /// POD struct line B
11399 struct B {
11400 /// Field line A
11401 /// Field line B
11402 uint32_t b;
11403
11404 /// Method line A
11405 /// Method line B
11406 void foo() {}
11407 };
11408
11409 /// Enum line A
11410 /// Enum line B
11411 enum C {
11412 /// Variant line A
11413 /// Variant line B
11414 VARIANT,
11415 };
11416
11417 /// Function line A
11418 /// Function line B
11419 inline void D() {}
11420 "};
11421
11422 let expected_messages = [
11423 "Struct",
11424 "POD struct",
11425 "Field",
11426 "Method",
11427 "Enum",
11428 "Variant",
11429 "Function",
11430 ]
11431 .into_iter()
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070011432 .flat_map(|l| [format!("{l} line A"), format!("{l} line B")])
Brian Silverman4e662aa2022-05-11 23:10:19 -070011433 .collect_vec();
11434
11435 run_test_ex(
11436 "",
11437 hdr,
11438 quote! {},
11439 directives_from_lists(&["A", "C", "D"], &["B"], None),
11440 None,
11441 Some(make_string_finder(expected_messages)),
11442 None,
11443 );
11444}
11445
11446#[test]
11447fn optional_param_in_copy_constructor() {
11448 let hdr = indoc! {"
11449 struct A {
11450 A(const A &other, bool optional_arg = false);
11451 };
11452 "};
11453 run_test("", hdr, quote! {}, &["A"], &[]);
11454}
11455
11456#[test]
11457fn param_in_copy_constructor() {
11458 let hdr = indoc! {"
11459 struct A {
11460 A(const A &other, bool arg);
11461 };
11462 "};
11463 run_test("", hdr, quote! {}, &["A"], &[]);
11464}
11465
11466#[test]
11467fn test_variadic() {
11468 let hdr = indoc! {"
11469 class SomeClass{
11470 public:
11471 inline void foo(int, ... ) {}
11472 };
11473 "};
11474 run_test("", hdr, quote! {}, &["SomeClass"], &[]);
11475}
11476
11477#[test]
11478fn test_typedef_to_enum() {
11479 let hdr = indoc! {"
11480 enum b {};
11481 class c {
11482 public:
11483 typedef b d;
11484 d e();
11485 };
11486 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011487 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011488}
11489
11490#[test]
11491fn test_typedef_to_ns_enum() {
11492 let hdr = indoc! {"
11493 namespace a {
11494 enum b {};
11495 class c {
11496 public:
11497 typedef b d;
11498 d e();
11499 };
11500 } // namespace
11501 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011502 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011503}
11504
11505#[test]
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070011506fn test_enum_in_ns() {
11507 let hdr = indoc! {"
11508 namespace a {
11509 enum b {};
11510 } // namespace
11511 "};
11512 run_test("", hdr, quote! {}, &["a::b"], &[]);
11513}
11514
11515#[test]
11516fn test_recursive_field() {
11517 let hdr = indoc! {"
11518 #include <memory>
11519 struct A {
11520 std::unique_ptr<A> a;
11521 };
11522 "};
11523 run_test("", hdr, quote! {}, &["A"], &[]);
11524}
11525
11526#[test]
11527fn test_recursive_field_indirect() {
11528 let hdr = indoc! {"
11529 #include <memory>
11530 struct B;
11531 struct A {
11532 std::unique_ptr<B> a;
11533 };
11534 struct B {
11535 std::unique_ptr<A> a1;
11536 A a2;
11537 };
11538 "};
11539 run_test("", hdr, quote! {}, &["A", "B"], &[]);
11540}
11541
11542#[test]
Brian Silverman4e662aa2022-05-11 23:10:19 -070011543fn test_typedef_unsupported_type_pub() {
11544 let hdr = indoc! {"
11545 #include <set>
11546 namespace NS{
11547 class cls{
11548 public:
11549 typedef std::set<int> InnerType;
11550 };
11551 }
11552 "};
11553
11554 run_test_ex(
11555 "",
11556 hdr,
11557 quote! {},
11558 quote! { generate_ns!("NS") },
11559 None,
11560 None,
11561 None,
11562 );
11563}
11564
11565#[test]
11566fn test_typedef_unsupported_type_pri() {
11567 let hdr = indoc! {"
11568 #include <set>
11569 namespace NS{
11570 class cls{
11571 private:
11572 typedef std::set<int> InnerType;
11573 };
11574 }
11575 "};
11576
11577 run_test_ex(
11578 "",
11579 hdr,
11580 quote! {},
11581 quote! { generate_ns!("NS") },
11582 None,
11583 None,
11584 None,
11585 );
11586}
11587
11588#[test]
11589fn test_array_trouble1() {
11590 let hdr = indoc! {"
11591 namespace a {
11592 template <typename b> struct array {
11593 typedef b c;
11594 typedef c d;
11595 };
11596 } // namespace a
11597 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011598 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011599}
11600
11601#[test]
11602fn test_array_trouble2() {
11603 let hdr = indoc! {"
11604 template <typename b> struct array {
11605 typedef b c;
11606 typedef c d;
11607 };
11608 "};
11609 run_test("", hdr, quote! {}, &["array_d"], &[]);
11610}
11611
11612#[test]
11613fn test_issue_1087a() {
11614 let hdr = indoc! {"
11615 template <typename _CharT> class a {
11616 _CharT b;
11617 };
11618 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011619 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011620}
11621
11622#[test]
11623fn test_issue_1087b() {
11624 let hdr = indoc! {"
11625 template <typename _CharT> class a {
11626 typedef _CharT b;
11627 b c;
11628 };
11629 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011630 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011631}
11632
11633#[test]
11634fn test_issue_1087c() {
11635 let hdr = indoc! {"
11636 namespace {
11637 namespace {
11638 template <typename _CharT> class a {
11639 typedef _CharT b;
11640 b c;
11641 };
11642 }
11643 }
11644 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011645 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011646}
11647
11648#[test]
11649fn test_issue_1089() {
11650 let hdr = indoc! {"
11651 namespace a {
11652 template <typename c, c> struct d;
11653 template <bool, typename, typename> struct ab;
11654 inline namespace {
11655 namespace ac {
11656 template <typename, template <typename> class, typename> struct bh;
11657 template <template <typename> class ad, typename... bi>
11658 using bj = bh<void, ad, bi...>;
11659 template <typename ad> using bk = typename ad::b;
11660 template <typename> struct bm;
11661 } // namespace ac
11662 template <typename ad>
11663 struct b : ab<ac::bj<ac::bk, ad>::e, ac::bm<ad>, d<bool, ad ::e>>::bg {};
11664 } // namespace
11665 } // namespace a
11666 "};
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011667 run_generate_all_test(hdr);
11668}
11669
11670/// The problem here is that 'g' doesn't get annotated with
11671/// the unused_template semantic attribute.
11672/// This seems to be because both g and f have template
11673/// parameters, so they're all "used", but effectively cancel
11674/// out and thus bindgen generates
11675/// pub type g = root::b::f;
11676/// So, what we should do here is spot any typedef depending
11677/// on a template which takes template args, and reject that too.
11678/// Probably.
11679#[test]
11680#[ignore] // https://github.com/google/autocxx/pull/1094
11681fn test_issue_1094() {
11682 let hdr = indoc! {"
11683 namespace {
11684 typedef int a;
11685 }
11686 namespace b {
11687 template <typename> struct c;
11688 template <typename d, d e> using f = __make_integer_seq<c, d, e>;
11689 template <a e> using g = f<a, e>;
11690 } // namespace b
11691 "};
11692 run_generate_all_test(hdr);
11693}
11694
11695#[test]
11696fn test_issue_1096a() {
11697 let hdr = indoc! {"
11698 namespace a {
11699 class b {
11700 class c;
11701 };
11702 } // namespace a
11703 "};
11704 run_generate_all_test(hdr);
11705}
11706
11707#[test]
11708fn test_issue_1096b() {
11709 let hdr = indoc! {"
11710 namespace a {
11711 class b {
11712 public:
11713 class c;
11714 };
11715 } // namespace a
11716 "};
11717 run_generate_all_test(hdr);
11718}
11719
11720#[test]
11721fn test_issue_1096c() {
11722 let hdr = indoc! {"
11723 namespace a {
11724 class b {
11725 public:
11726 class c {
11727 public:
11728 int d;
11729 };
11730 };
11731 } // namespace a
11732 "};
11733 run_generate_all_test(hdr);
11734}
11735
11736#[test]
11737fn test_issue_1096d() {
11738 let hdr = indoc! {"
11739 namespace a {
11740 class b {
11741 private:
11742 class c {
11743 public:
11744 int d;
11745 };
11746 };
11747 } // namespace a
11748 "};
11749 run_generate_all_test(hdr);
11750}
11751
11752#[test]
11753fn test_issue_1096e() {
11754 let hdr = indoc! {"
11755 namespace a {
11756 class b {
11757 private:
11758 enum c {
11759 D,
11760 };
11761 };
11762 } // namespace a
11763 "};
11764 run_generate_all_test(hdr);
11765}
11766
11767/// Unclear why minimization resulted in this particular test case.
11768#[test]
11769#[ignore] // https://github.com/google/autocxx/pull/1097
11770fn test_issue_1097() {
11771 let hdr = indoc! {"
11772 namespace rust {
11773 inline namespace a {
11774 class Str {
11775 public:
11776 ~Str();
11777 };
11778 } // namespace a
11779 } // namespace rust
11780 "};
11781 run_generate_all_test(hdr);
11782}
11783
11784#[test]
11785fn test_issue_1098a() {
11786 let hdr = indoc! {"
11787 namespace {
11788 namespace {
11789 template <typename _CharT> class a {
11790 typedef _CharT b;
11791 b c;
11792 };
11793 template <typename _CharT> class d : a<_CharT> {};
11794 } // namespace
11795 } // namespace
11796 "};
11797 run_generate_all_test(hdr);
11798}
11799
11800/// Need to spot structs like this:
11801/// pub struct d<_CharT> {
11802/// _base: root::a<_CharT>,
11803/// }
11804/// and not create concrete types where the inner type is something from
11805/// the outer context.
11806#[test]
11807fn test_issue_1098b() {
11808 let hdr = indoc! {"
11809 template <typename _CharT> class a {
11810 typedef _CharT b;
11811 b c;
11812 };
11813 template <typename _CharT> class d : a<_CharT> {};
11814 "};
11815 run_generate_all_test(hdr);
11816}
11817
11818#[test]
11819fn test_issue_1098c() {
11820 let hdr = indoc! {"
11821 namespace {
11822 namespace {
11823 struct A {
11824 int a;
11825 };
11826 typedef A B;
11827 } // namespace
11828 } // namespace
11829 inline void take_b(const B&) {}
11830 "};
11831 run_generate_all_test(hdr);
Brian Silverman4e662aa2022-05-11 23:10:19 -070011832}
11833
11834#[test]
11835fn test_pass_rust_str_and_return_struct() {
11836 let cxx = indoc! {"
11837 A take_str_return_struct(rust::Str) {
11838 A a;
11839 return a;
11840 }
11841 "};
11842 let hdr = indoc! {"
11843 #include <cxx.h>
11844 struct A {};
11845 A take_str_return_struct(rust::Str);
11846 "};
11847 let rs = quote! {
11848 ffi::take_str_return_struct("hi");
11849 };
11850 run_test(cxx, hdr, rs, &["take_str_return_struct"], &[]);
11851}
11852
11853#[test]
11854fn test_issue_1065a() {
11855 let hdr = indoc! {"
11856 #include <memory>
11857 #include <vector>
11858
11859 template <typename at> class au {
11860 std::unique_ptr<at> aw;
11861 };
11862 class bb;
11863 using bc = au<bb>;
11864 class RenderFrameHost {
11865 public:
11866 virtual std::vector<bc> &bd() = 0;
11867 virtual ~RenderFrameHost() {}
11868 };
11869 "};
11870 let rs = quote! {};
11871 run_test("", hdr, rs, &["RenderFrameHost"], &[]);
11872}
11873
11874#[test]
11875fn test_issue_1065b() {
11876 let hdr = indoc! {"
11877 #include <memory>
11878 #include <vector>
11879
11880 class bb;
11881 using bc = std::unique_ptr<bb>;
11882 class RenderFrameHost {
11883 public:
11884 virtual std::vector<bc> &bd() = 0;
11885 virtual ~RenderFrameHost() {}
11886 };
11887 "};
11888 let rs = quote! {};
11889 run_test("", hdr, rs, &["RenderFrameHost"], &[]);
11890}
11891
Brian Silvermanf3ec38b2022-07-06 20:43:36 -070011892#[test]
11893fn test_issue_1081() {
11894 let hdr = indoc! {"
11895 namespace libtorrent {
11896 char version;
11897 }
11898 namespace libtorrent {
11899 struct session;
11900 }
11901 "};
11902 let rs = quote! {};
11903 run_test("", hdr, rs, &["libtorrent::session"], &[]);
11904}
11905
11906#[test]
11907#[ignore] // This test passes under all normal builds. However
11908 // it triggers a stack use-after-return in older versions of
11909 // libclang which is only detected under ASAN (obviously it
11910 // sometimes causes crashes the rest of the time).
11911 // This UaR does not occur when the same code is processed
11912 // with a HEAD version of clang itself as of June 2022. This
11913 // may mean that the UaR has been fixed in later versions of
11914 // the clang code, or that it only occurs when the code is used
11915 // in a libclang context (not a plain clang compilation context).
11916 // If the problem recurs, we should work out which of these is
11917 // the case.
11918fn test_issue_1125() {
11919 let hdr = indoc! {"
11920 namespace {
11921 namespace {
11922 template <class a> class b {
11923 typedef a c;
11924 struct {
11925 c : sizeof(c);
11926 };
11927 };
11928 } // namespace
11929 } // namespace
11930 "};
11931 run_test_ex(
11932 "",
11933 hdr,
11934 quote! {},
11935 quote! {
11936 generate_all!()
11937 },
11938 make_cpp17_adder(),
11939 None,
11940 None,
11941 );
11942}
11943
Austin Schuh6ea9bfa2023-08-06 19:05:10 -070011944#[test]
11945fn test_issue_1143() {
11946 let hdr = indoc! {
11947 "namespace mapnik {
11948 class Map {
11949 public:
11950 int &a(long);
11951 };
11952 }"
11953 };
11954
11955 run_test("", hdr, quote! {}, &["mapnik::Map"], &[]);
11956}
11957
11958#[test]
11959fn test_issue_1170() {
11960 let hdr = indoc! {
11961 "#include <vector>
11962 struct a {
11963 enum b {} c;
11964 } Loc;
11965 struct Arch {
11966 std::vector<a> d();
11967 } DeterministicRNG;"
11968 };
11969 run_test("", hdr, quote! {}, &["Arch"], &[]);
11970}
11971
11972// https://github.com/google/autocxx/issues/774
11973#[test]
11974fn test_virtual_methods() {
11975 let hdr = indoc! {"
11976 #include <cstdint>
11977 #include <memory>
11978 class Base {
11979 public:
11980 Base() {}
11981 virtual ~Base() {}
11982
11983 virtual int a() = 0;
11984
11985 virtual void b(int) = 0;
11986 virtual void b(bool) = 0;
11987
11988 virtual int c() const = 0;
11989 virtual int c() = 0;
11990 };
11991 class FullyDefined : public Base {
11992 public:
11993 int a() { return 0; }
11994
11995 void b(int) { }
11996 void b(bool) { }
11997
11998 int c() const { return 1; }
11999 int c() { return 2; }
12000 };
12001 class Partial1 : public Base {
12002 public:
12003 int a() { return 0; }
12004
12005 void b(bool) {}
12006 };
12007
12008 class Partial2 : public Base {
12009 public:
12010 int a() { return 0; }
12011
12012 void b(int) { }
12013 void b(bool) { }
12014
12015 int c() const { return 1; }
12016 };
12017
12018 class Partial3 : public Base {
12019 public:
12020 int a() { return 0; }
12021
12022 void b(int) { }
12023
12024 int c() const { return 1; }
12025 int c() { return 2; }
12026 };
12027
12028 class Partial4 : public Base {
12029 public:
12030 int a() { return 0; }
12031
12032 void b(int) { }
12033 void b(bool) = 0;
12034
12035 int c() const { return 1; }
12036 int c() { return 2; }
12037 };
12038
12039 // TODO: currently this class cannot be detected as virtual as there
12040 // is no metadata captured to show that this destructor is virtual
12041 // uncommenting this (as well as corresponding sections below) gives a
12042 // 'instantiation of abstract class' error.
12043 // class Partial5 : public Base {
12044 // public:
12045 // ~Partial5() = 0;
12046
12047 // int a() { return 0; }
12048
12049 // void b(int) { }
12050 // void b(bool) { }
12051
12052 // int c() const { return 1; }
12053 // int c() { return 2; }
12054 // };
12055
12056 "};
12057 let rs = quote! {
12058 static_assertions::assert_impl_all!(ffi::FullyDefined: moveit::CopyNew);
12059 static_assertions::assert_not_impl_any!(ffi::Partial1: moveit::CopyNew);
12060 static_assertions::assert_not_impl_any!(ffi::Partial2: moveit::CopyNew);
12061 static_assertions::assert_not_impl_any!(ffi::Partial3: moveit::CopyNew);
12062 static_assertions::assert_not_impl_any!(ffi::Partial4: moveit::CopyNew);
12063 // static_assertions::assert_not_impl_any!(ffi::Partial5: moveit::CopyNew);
12064 let _c1 = ffi::FullyDefined::new().within_unique_ptr();
12065 };
12066 run_test(
12067 "",
12068 hdr,
12069 rs,
12070 &[
12071 "FullyDefined",
12072 "Partial1",
12073 "Partial2",
12074 "Partial3",
12075 "Partial4",
12076 // "Partial5"
12077 ],
12078 &[],
12079 );
12080}
12081
12082#[test]
12083fn test_issue_1192() {
12084 let hdr = indoc! {
12085 "#include <vector>
12086 #include <cstdint>
12087 template <typename B>
12088 struct A {
12089 B a;
12090 };
12091 struct VecThingy {
12092 A<uint32_t> contents[2];
12093 };
12094 struct MyStruct {
12095 VecThingy vec;
12096 };"
12097 };
12098 run_test_ex(
12099 "",
12100 hdr,
12101 quote! {},
12102 quote! {
12103
12104 extern_cpp_type!("VecThingy", crate::VecThingy)
12105 pod!("VecThingy")
12106
12107 generate_pod!("MyStruct")
12108 },
12109 None,
12110 None,
12111 Some(quote! {
12112 // VecThingy isn't necessarily 128 bits long.
12113 // This test doesn't actually allocate one.
12114 #[repr(transparent)]
12115 pub struct VecThingy(pub u128);
12116
12117 unsafe impl cxx::ExternType for VecThingy {
12118 type Id = cxx::type_id!("VecThingy");
12119 type Kind = cxx::kind::Trivial;
12120 }
12121 }),
12122 );
12123}
12124
12125#[test]
12126fn test_issue_1214() {
12127 let hdr = indoc! {"
12128 #include <cstdint>
12129 enum class C: uint16_t {
12130 A,
12131 B,
12132 };
12133 "};
12134 run_test("", hdr, quote! {}, &["C"], &[]);
12135}
12136
12137#[test]
12138fn test_issue_1229() {
12139 let hdr = indoc! {"
12140 struct Thing {
12141 float id;
12142
12143 Thing(float id) : id(id) {}
12144 };
12145
12146 struct Item {
12147 float id;
12148
12149 Item(float id) : id(id) {}
12150 };
12151 "};
12152 let hexathorpe = Token![#](Span::call_site());
12153 let rs = quote! {
12154 use autocxx::WithinUniquePtr;
12155
12156 autocxx::include_cpp! {
12157 #hexathorpe include "input.h"
12158 name!(thing)
12159 safety!(unsafe)
12160 generate!("Thing")
12161 }
12162 autocxx::include_cpp! {
12163 #hexathorpe include "input.h"
12164 name!(item)
12165 safety!(unsafe)
12166 generate!("Item")
12167 }
12168
12169 fn main() {
12170 let _thing = thing::Thing::new(15.).within_unique_ptr();
12171 let _item = item::Item::new(15.).within_unique_ptr();
12172 }
12173 };
12174
12175 do_run_test_manual("", hdr, rs, None, None).unwrap();
12176}
12177
12178#[test]
12179#[ignore] // https://github.com/google/autocxx/issues/1265
12180fn test_issue_1265() {
12181 let hdr = indoc! {"
12182 #include <string>
12183
12184 class Test
12185 {
12186 public:
12187 explicit Test(std::string string)
12188 : string(std::move(string))
12189 {
12190 }
12191
12192 Test() = delete;
12193
12194 [[nodiscard]] auto get_string() const -> std::string const& { return this->string; }
12195
12196 private:
12197 std::string string;
12198 };
12199 "};
12200 run_test_ex(
12201 "",
12202 hdr,
12203 quote! {
12204 run();
12205 },
12206 directives_from_lists(&["Test"], &[], None),
12207 None,
12208 None,
12209 Some(quote! {
12210 fn run() {
12211 let str0 = "string";
12212 let str1 = "another string";
12213 let ptr0 = UniquePtr::emplace(ffi::Test::new(str0));
12214 let ptr1 = UniquePtr::emplace(ffi::Test::new(str1));
12215 println!("0: {}", ptr0.get_string());
12216 println!("1: {}", ptr1.get_string());
12217 moveit!(let mut ref0 = &move *ptr0);
12218 moveit!(let mut ref1 = &move *ptr1);
12219 println!("0: {}", ref0.get_string());
12220 println!("1: {}", ref1.get_string());
12221 println!("swap");
12222 core::mem::swap(&mut *ref0, &mut *ref1);
12223 println!("0: {}", ref0.get_string());
12224 println!("1: {}", ref1.get_string());
12225 }
12226 }),
12227 )
12228}
12229
12230#[test]
12231fn test_ignore_va_list() {
12232 let hdr = indoc! {"
12233 #include <stdarg.h>
12234 class A {
12235 public:
12236 A() {}
12237 void fn(va_list) {}
12238 };
12239 "};
12240 let rs = quote! {};
12241 run_test("", hdr, rs, &["A"], &[]);
12242}
12243
Brian Silverman4e662aa2022-05-11 23:10:19 -070012244// Yet to test:
12245// - Ifdef
12246// - Out param pointers
12247// - ExcludeUtilities
12248// - Struct fields which are typedefs
12249// Negative tests:
12250// - Private methods
12251// - Private fields