Merge pull request #15 from google:ssbr-patch-1 PiperOrigin-RevId: 822327211 Change-Id: If02bb2932506d25d4ecc054203cb2a000552f9a9
diff --git a/Cargo.toml b/Cargo.toml index dd1de12..70dc8d8 100644 --- a/Cargo.toml +++ b/Cargo.toml
@@ -15,20 +15,21 @@ # will be decided from here. [workspace.dependencies] anyhow = "1" +clap = { version = "4", features = [ "derive" ] } +either = "1" flagset = "0.4" +heck = "0.5" itertools = "0.13" +phf = { version = "0.11", features = [ "macros" ] } proc-macro2 = "1" +quote = "1" regex = "1" +rustversion = "1" serde = { version = "1", features = [ "derive", "rc" ] } serde_json = "1" syn = { version = "2", features = [ "extra-traits" ] } -quote = "1" +tracing = "0.1" unicode-ident = "1" -either = "1" -clap = { version = "4", features = [ "derive" ] } -rustversion = "1" -heck = "0.5" -phf = { version = "0.11", features = [ "macros" ] } [workspace.package]
diff --git a/WORKSPACE.bzlmod b/WORKSPACE.bzlmod index 66ee456..33e2df3 100644 --- a/WORKSPACE.bzlmod +++ b/WORKSPACE.bzlmod
@@ -122,6 +122,9 @@ "tempfile": crate.spec( version = "=3.4.0", ), + "tracing": crate.spec( + version = ">=0.1.41", + ), "unicode-ident": crate.spec( version = ">0.0.0", ),
diff --git a/bazel/llvm.bzl b/bazel/llvm.bzl index 026eb46..fb2823e 100644 --- a/bazel/llvm.bzl +++ b/bazel/llvm.bzl
@@ -53,7 +53,7 @@ executable = False, ) -LLVM_COMMIT_SHA = "891f002026df122b36813b9e1819769c94327503" +LLVM_COMMIT_SHA = "32de3b9ef9e7e8debc14416e968456ca13b48bea" def llvm_loader_repository_dependencies(): # This *declares* the dependency, but it won't actually be *downloaded* unless it's used.
diff --git a/cc_bindings_from_rs/BUILD b/cc_bindings_from_rs/BUILD index 83f7f76..2e693a4 100644 --- a/cc_bindings_from_rs/BUILD +++ b/cc_bindings_from_rs/BUILD
@@ -33,9 +33,9 @@ "//common:crubit_feature", "//common:error_report", "//common:token_stream_printer", - "@crate_index//:clap", - "@crate_index//:flagset", - "@crate_index//:itertools", + "@crate_index//:clap", # v4 + "@crate_index//:flagset", # v0_4 + "@crate_index//:itertools", # v0_13 ], ) @@ -49,8 +49,8 @@ tags = ["not_run:mac"], deps = [ ":run_compiler_test_support", - "@crate_index//:regex", - "@crate_index//:tempfile", + "@crate_index//:regex", # v1 + "@crate_index//:tempfile", # v3 ], ) @@ -79,9 +79,9 @@ deps = [ "//common:crubit_feature", "//common:dyn_format", - "@crate_index//:anyhow", - "@crate_index//:clap", - "@crate_index//:flagset", + "@crate_index//:anyhow", # v1 + "@crate_index//:clap", # v4 + "@crate_index//:flagset", # v0_4 ], ) @@ -95,8 +95,8 @@ tags = ["not_run:mac"], deps = [ ":run_compiler_test_support", - "@crate_index//:itertools", - "@crate_index//:tempfile", + "@crate_index//:itertools", # v0_13 + "@crate_index//:tempfile", # v3 ], ) @@ -104,13 +104,13 @@ name = "crubit_attr", srcs = ["crubit_attr.rs"], proc_macro_deps = [ - "@crate_index//:rustversion", + "@crate_index//:rustversion", # v1 ], # LINT.IfChange rustc_flags = ["-Zallow-features=rustc_private"], # LINT.ThenChange(//docs/overview/unstable_features.md) deps = [ - "@crate_index//:anyhow", + "@crate_index//:anyhow", # v1 ], ) @@ -125,7 +125,7 @@ deps = [ ":crubit_attr", ":run_compiler_test_support", - "@crate_index//:anyhow", + "@crate_index//:anyhow", # v1 ], ) @@ -135,14 +135,14 @@ "run_compiler.rs", ], proc_macro_deps = [ - "@crate_index//:rustversion", + "@crate_index//:rustversion", # v1 ], # LINT.IfChange rustc_flags = ["-Zallow-features=rustc_private,cfg_accessible"], # LINT.ThenChange(//docs/overview/unstable_features.md) deps = [ "//common:arc_anyhow", - "@crate_index//:either", + "@crate_index//:either", # v1 ], ) @@ -156,7 +156,7 @@ tags = ["not_run:mac"], deps = [ ":run_compiler_test_support", - "@crate_index//:tempfile", + "@crate_index//:tempfile", # v3 ], ) @@ -170,11 +170,11 @@ "@rust_linux_x86_64__x86_64-unknown-linux-gnu__nightly_tools//:rust_std-x86_64-unknown-linux-gnu", ], proc_macro_deps = [ - "@crate_index//:rustversion", + "@crate_index//:rustversion", # v1 ], rustc_flags = ["--cfg=oss"], deps = [ - "@crate_index//:itertools", + "@crate_index//:itertools", # v0_13 "@rules_rust//tools/runfiles", ], )
diff --git a/cc_bindings_from_rs/bazel_support/cc_bindings_from_rust_rule.bzl b/cc_bindings_from_rs/bazel_support/cc_bindings_from_rust_rule.bzl index b12aa65..f091d76 100644 --- a/cc_bindings_from_rs/bazel_support/cc_bindings_from_rust_rule.bzl +++ b/cc_bindings_from_rs/bazel_support/cc_bindings_from_rust_rule.bzl
@@ -312,8 +312,8 @@ ) dep_info, build_info, linkstamps = collect_deps( - deps = crate_info.deps, - proc_macro_deps = crate_info.proc_macro_deps, + deps = crate_info.deps.to_list(), + proc_macro_deps = crate_info.proc_macro_deps.to_list(), aliases = crate_info.aliases, )
diff --git a/cc_bindings_from_rs/cc_bindings_from_rs.rs b/cc_bindings_from_rs/cc_bindings_from_rs.rs index 6d1078f..17c0ed5 100644 --- a/cc_bindings_from_rs/cc_bindings_from_rs.rs +++ b/cc_bindings_from_rs/cc_bindings_from_rs.rs
@@ -112,15 +112,17 @@ } { - let cc_api = cc_tokens_to_formatted_string(cc_api, &cmdline.clang_format_exe_path)?; + let cc_api = + cc_tokens_to_formatted_string(cc_api, cmdline.clang_format_exe_path.as_deref())?; let cc_api = turn_off_clang_format(cc_api); write_file(&cmdline.h_out, &cc_api)?; } { - let rustfmt_config = - RustfmtConfig::new(&cmdline.rustfmt_exe_path, cmdline.rustfmt_config_path.as_deref()); - let cc_api_impl = rs_tokens_to_formatted_string(cc_api_impl, &rustfmt_config)?; + let rustfmt_config = cmdline.rustfmt_exe_path.as_ref().map(|rustfmt_path| { + RustfmtConfig::new(rustfmt_path, cmdline.rustfmt_config_path.as_deref()) + }); + let cc_api_impl = rs_tokens_to_formatted_string(cc_api_impl, rustfmt_config.as_ref())?; write_file(&cmdline.rs_out, &cc_api_impl)?; }
diff --git a/cc_bindings_from_rs/cmdline.rs b/cc_bindings_from_rs/cmdline.rs index 68a8159..ab8e3a6 100644 --- a/cc_bindings_from_rs/cmdline.rs +++ b/cc_bindings_from_rs/cmdline.rs
@@ -54,9 +54,9 @@ pub crubit_debug_path_format: Option<Format<2>>, /// Path to a clang-format executable that will be used to format the - /// C++ header files generated by the tool. + /// C++ header files generated by the tool. If omitted, generated code will not be formatted. #[clap(long, value_parser, value_name = "FILE")] - pub clang_format_exe_path: PathBuf, + pub clang_format_exe_path: Option<PathBuf>, /// Include paths of bindings for dependency crates, generated by previous /// invocations of Crubit. Keys are crate names, and values are include @@ -100,12 +100,13 @@ pub crate_disabled_features: Vec<(String, flagset::FlagSet<crubit_feature::CrubitFeature>)>, /// Path to a rustfmt executable that will be used to format the - /// Rust source files generated by the tool. + /// Rust source files generated by the tool. If omitted, generated code will not be formatted. #[clap(long, value_parser, value_name = "FILE")] - pub rustfmt_exe_path: PathBuf, + pub rustfmt_exe_path: Option<PathBuf>, /// Path to a rustfmt.toml file that should replace the - /// default formatting of the .rs files generated by the tool. + /// default formatting of the .rs files generated by the tool. This flag is only used if + /// rustfmt_exe_path is specified. #[clap(long, value_parser, value_name = "FILE")] pub rustfmt_config_path: Option<PathBuf>, @@ -292,8 +293,8 @@ Format::parse_with_metavars("<crubit/support/{header}>", &["header"]).unwrap(), cmdline.crubit_support_path_format, ); - assert_eq!(Path::new("clang-format.exe"), cmdline.clang_format_exe_path); - assert_eq!(Path::new("rustfmt.exe"), cmdline.rustfmt_exe_path); + assert_eq!(Some(PathBuf::from("clang-format.exe")), cmdline.clang_format_exe_path); + assert_eq!(Some(PathBuf::from("rustfmt.exe")), cmdline.rustfmt_exe_path); assert!(cmdline.crate_headers.is_empty()); assert!(cmdline.rustfmt_config_path.is_none()); // Ignoring `rustc_args` in this test - they are covered in a separate @@ -472,4 +473,30 @@ "Invalid Crubit feature name: \"\"", ); } + + #[test] + fn test_omit_rustfmt_exe_path() { + let cmdline = new_cmdline([ + "--h-out=foo.h", + "--rs-out=foo_impl.rs", + "--crubit-support-path-format=<crubit/support/{header}>", + "--clang-format-exe-path=clang-format.exe", + ]) + .unwrap(); + assert_eq!(Some(PathBuf::from("clang-format.exe")), cmdline.clang_format_exe_path); + assert_eq!(None, cmdline.rustfmt_exe_path); + } + + #[test] + fn test_omit_clang_format_exe_path() { + let cmdline = new_cmdline([ + "--h-out=foo.h", + "--rs-out=foo_impl.rs", + "--crubit-support-path-format=<crubit/support/{header}>", + "--rustfmt-exe-path=rustfmt.exe", + ]) + .unwrap(); + assert_eq!(None, cmdline.clang_format_exe_path); + assert_eq!(Some(PathBuf::from("rustfmt.exe")), cmdline.rustfmt_exe_path); + } }
diff --git a/cc_bindings_from_rs/generate_bindings/BUILD b/cc_bindings_from_rs/generate_bindings/BUILD index 0515f43..ebc9a8b 100644 --- a/cc_bindings_from_rs/generate_bindings/BUILD +++ b/cc_bindings_from_rs/generate_bindings/BUILD
@@ -24,7 +24,7 @@ "lib.rs", ], proc_macro_deps = [ - "@crate_index//:rustversion", + "@crate_index//:rustversion", # v1 ], # LINT.IfChange rustc_flags = ["-Zallow-features=rustc_private,rustc_attr,cfg_accessible,stmt_expr_attributes,proc_macro_hygiene"], @@ -41,11 +41,11 @@ "//common:crubit_feature", "//common:dyn_format", "//common:error_report", - "@crate_index//:flagset", - "@crate_index//:itertools", + "@crate_index//:flagset", # v0_4 + "@crate_index//:itertools", # v0_13 "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:syn", # v1 ], ) @@ -60,7 +60,7 @@ "//common:code_gen_utils", "//common:token_stream_matchers", "@crate_index//:proc-macro2", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -75,7 +75,7 @@ "//common:token_stream_matchers", "//common:token_stream_printer", "@crate_index//:proc-macro2", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -87,9 +87,9 @@ "//common:code_gen_utils", "//common:crubit_feature", "//common:token_stream_matchers", - "@crate_index//:flagset", + "@crate_index//:flagset", # v0_4 "@crate_index//:proc-macro2", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -99,7 +99,7 @@ deps = [ ":test_helpers", "//common:token_stream_matchers", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -123,7 +123,7 @@ "//common:crubit_feature", "//common:dyn_format", "//common:error_report", - "@crate_index//:flagset", + "@crate_index//:flagset", # v0_4 ], )
diff --git a/cc_bindings_from_rs/generate_bindings/database/BUILD b/cc_bindings_from_rs/generate_bindings/database/BUILD index 1555a63..6911315 100644 --- a/cc_bindings_from_rs/generate_bindings/database/BUILD +++ b/cc_bindings_from_rs/generate_bindings/database/BUILD
@@ -34,9 +34,9 @@ "//common:dyn_format", "//common:error_report", "//common:memoized", - "@crate_index//:flagset", - "@crate_index//:itertools", + "@crate_index//:flagset", # v0_4 + "@crate_index//:itertools", # v0_13 "@crate_index//:proc-macro2", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], )
diff --git a/cc_bindings_from_rs/generate_bindings/format_type.rs b/cc_bindings_from_rs/generate_bindings/format_type.rs index 6a6f060..d44b9b2 100644 --- a/cc_bindings_from_rs/generate_bindings/format_type.rs +++ b/cc_bindings_from_rs/generate_bindings/format_type.rs
@@ -186,7 +186,7 @@ return None; }; - if !matches_qualified_name(db, adt.did(), ":: core :: mem :: maybe_uninit :: MaybeUninit") + if !matches_qualified_name(db, adt.did(), &["core", "mem", "maybe_uninit", "MaybeUninit"]) || substs.len() != 1 { return None; @@ -252,27 +252,11 @@ prereqs.includes.insert(CcInclude::array()); // We need to be able to handle expressions at the type level that are not simple // numeric literals. - let normalized = match db.tcx().try_normalize_erasing_regions( - ty::TypingEnv { - typing_mode: ty::TypingMode::PostAnalysis, - param_env: ty::ParamEnv::empty(), - }, - *length, - ) { - Ok(normalized) => normalized, - Err(_) => { - panic!("Unable to normalize array length {{length}}.") - } - }; - let Some(target_usize) = normalized.try_to_target_usize(db.tcx()) else { - panic!( - "Unable to get array length from normalized type ({length} => {normalized})." - ) - }; + let target_size = evaluate_const_as_u64(db.tcx(), *length); let sugared_element_type = SugaredTy::missing_hir(*element_type); let cc_element_ty = db.format_ty_for_cc(sugared_element_type, location)?.into_tokens(&mut prereqs); - let c_int = Literal::u64_unsuffixed(target_usize); + let c_int = Literal::u64_unsuffixed(target_size); CcSnippet { prereqs, tokens: quote! { std::array<#cc_element_ty, #c_int> } } } @@ -758,7 +742,7 @@ ty: &Ty<'tcx>, ) -> Result<TokenStream> { if let ty::TyKind::Adt(adt, substs) = ty.kind() { - if matches_qualified_name(db, adt.did(), ":: core :: mem :: maybe_uninit :: MaybeUninit") { + if matches_qualified_name(db, adt.did(), &["core", "mem", "maybe_uninit", "MaybeUninit"]) { let generic_ty = db.format_ty_for_rs(substs[0].expect_ty())?; return Ok(quote! { std::mem::MaybeUninit<#generic_ty> }); } @@ -853,22 +837,8 @@ } ty::TyKind::Array(element_type, length) => { let rs_element_type = db.format_ty_for_rs(*element_type)?; - let normalized_length = match db.tcx().try_normalize_erasing_regions( - ty::TypingEnv { - typing_mode: ty::TypingMode::PostAnalysis, - param_env: ty::ParamEnv::empty(), - }, - *length, - ) { - Ok(normalized) => normalized, - Err(_) => { - panic!("Unable to normalize array length {{length}}.") - } - }; - let Some(target_usize) = normalized_length.try_to_target_usize(db.tcx()) else { - panic!("Unable to get array length from normalized type ({length} => {normalized_length}).") - }; - let unsuffixed_length = Literal::u64_unsuffixed(target_usize); + let target_size = evaluate_const_as_u64(db.tcx(), *length); + let unsuffixed_length = Literal::u64_unsuffixed(target_size); quote! { [ #rs_element_type; #unsuffixed_length ] } } ty::TyKind::Adt(adt, substs) => { @@ -1377,3 +1347,21 @@ _ => Ok(None), } } + +// Evaluates a constant (such as the length of an array type). +pub fn evaluate_const_as_u64<'tcx>(tcx: ty::TyCtxt<'tcx>, cst: ty::Const<'tcx>) -> u64 { + // It would be nice if we knew that these types were already fully normalized. + let normalized = tcx + .try_normalize_erasing_regions( + ty::TypingEnv { + typing_mode: ty::TypingMode::PostAnalysis, + param_env: ty::ParamEnv::empty(), + }, + cst, + ) + .unwrap_or_else(|_| panic!("Unable to normalize type constant {{cst}}.")); + let Some(target_u64) = normalized.try_to_target_usize(tcx) else { + panic!("Unable to get size from normalized type constant ({cst} => {normalized}).") + }; + target_u64 +}
diff --git a/cc_bindings_from_rs/generate_bindings/generate_function.rs b/cc_bindings_from_rs/generate_bindings/generate_function.rs index ab9fd58..bd05871 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_function.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_function.rs
@@ -385,6 +385,9 @@ #[rustversion::since(2025-07-29)] let impl_id = tcx.impl_of_assoc(def_id)?; + #[rustversion::since(2025-10-17)] + assert!(!tcx.impl_is_of_trait(impl_id), "Trait methods should be filtered by caller"); + #[rustversion::before(2025-10-17)] assert!(tcx.impl_trait_ref(impl_id).is_none(), "Trait methods should be filtered by caller"); Some(tcx.type_of(impl_id).instantiate_identity()) }
diff --git a/cc_bindings_from_rs/generate_bindings/generate_function_thunk.rs b/cc_bindings_from_rs/generate_bindings/generate_function_thunk.rs index 8dbf45a..da73b68 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_function_thunk.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_function_thunk.rs
@@ -50,6 +50,20 @@ Some(quote! { *const [*const core::ffi::c_void; #num_elements] }) } +/// Returns a C ABI-compatible C type to pass a [inner_ty; _]. +/// +/// Layout-compatible arrays are passed through memory. +fn array_c_abi_c_type(inner_ty: &ty::Ty) -> Result<TokenStream> { + // TODO: b/451981992 - Is this test enough to avoid nested by-value arrays? + // This is also more conservative than what we probably need here, which is to exclude + // nested arrays containing types that are Drop but not Default (as these don't behave + // well in std::arrays; we currently treat single-level arrays as a special case). + match inner_ty.kind() { + ty::TyKind::Array(..) => bail!("b/260128806 - nested array {inner_ty} is not supported"), + _ => Ok(quote! { void* }), + } +} + /// Formats a C++ declaration of a C-ABI-compatible-function wrapper around a Rust function. pub fn generate_thunk_decl<'tcx>( db: &dyn BindingsGenerator<'tcx>, @@ -86,6 +100,8 @@ Ok(quote! { #cpp_type }) } else if let Some(tuple_abi) = tuple_c_abi_c_type(ty) { Ok(tuple_abi) + } else if let ty::TyKind::Array(inner_ty, _) = ty.kind() { + array_c_abi_c_type(inner_ty) } else if let Some(adt_def) = ty.ty_adt_def() { let core = db.generate_adt_core(adt_def.did())?; db.generate_move_ctor_and_assignment_operator(core).map_err(|_| { @@ -106,6 +122,10 @@ } else if let Some(tuple_abi) = tuple_c_abi_c_type(sig_mid.output()) { thunk_ret_type = quote! { void }; thunk_params.push(quote! { #tuple_abi __ret_ptr }); + } else if let ty::TyKind::Array(inner_ty, _) = sig_mid.output().kind() { + let c_type = array_c_abi_c_type(inner_ty)?; + thunk_ret_type = quote! { void }; + thunk_params.push(quote! { #c_type __ret_ptr }); } else if let Some(BridgedType::Composable(_)) = is_bridged_type(db, sig_mid.output())? { thunk_ret_type = quote! { void }; thunk_params.push(quote! { unsigned char * __ret_ptr }); @@ -404,6 +424,8 @@ #unpack #write_elements } + } else if let ty::TyKind::Array { .. } = rs_type.kind() { + write_directly()? } else if rs_type.ty_adt_def().is_some() { write_directly()? } else {
diff --git a/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs b/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs index 41002b9..4e943b0 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs
@@ -335,6 +335,9 @@ }; let mut map: HashMap<Ty<'tcx>, Vec<DefId>> = HashMap::new(); for from_impl_id in impls_iter { + #[rustversion::since(2025-10-17)] + let middle_trait_header = tcx.impl_trait_header(from_impl_id); + #[rustversion::before(2025-10-17)] let middle_trait_header = tcx .impl_trait_header(from_impl_id) .expect("DefId for an `From` trait impl lacked a trait header"); @@ -366,6 +369,9 @@ let from_map = db.from_trait_impls_by_argument(core.def_id.krate); let from_impls = from_map.get(&core.self_ty).into_iter().flat_map(|vec| vec.iter()).filter_map( |from_impl_id| { + #[rustversion::since(2025-10-17)] + let middle_trait_header = tcx.impl_trait_header(*from_impl_id); + #[rustversion::before(2025-10-17)] let middle_trait_header = tcx .impl_trait_header(*from_impl_id) .expect("DefId for a `From` trait impl lacked a trait header"); @@ -387,6 +393,9 @@ ); let into_impls = tcx.non_blanket_impls_for_ty(into_trait, core.self_ty).filter_map(|into_impl_id| { + #[rustversion::since(2025-10-17)] + let middle_trait_header = tcx.impl_trait_header(into_impl_id); + #[rustversion::before(2025-10-17)] let middle_trait_header = tcx .impl_trait_header(into_impl_id) .expect("DefId for an `Into` trait impl lacked a trait header");
diff --git a/cc_bindings_from_rs/generate_bindings/lib.rs b/cc_bindings_from_rs/generate_bindings/lib.rs index f482ef7..52c896e 100644 --- a/cc_bindings_from_rs/generate_bindings/lib.rs +++ b/cc_bindings_from_rs/generate_bindings/lib.rs
@@ -461,15 +461,22 @@ name_map } -/// Checks whether a definition matches a specific qualified name. -fn matches_qualified_name( - db: &dyn BindingsGenerator<'_>, - item_did: DefId, - name_to_compare: &str, -) -> bool { - // TODO(b/372153103): Compare the name via `tcx.def_path(adt.did())`. - let type_name = FullyQualifiedName::new(db, item_did); - type_name.format_for_rs().to_string() == name_to_compare +/// Checks whether a definition matches a specific qualified name by matching it's definition path +/// against `name`. Name must include the crate in it's path. +fn matches_qualified_name(db: &dyn BindingsGenerator<'_>, item_did: DefId, name: &[&str]) -> bool { + let tcx = db.tcx(); + let path = tcx.def_path(item_did); + if path.data.len() + 1 != name.len() { + return false; + } + // This will always return false for anonymous path data because the caller won't be able to + // specify the `disambiguator` that gets inserted into the symbol. That's fine. It is expected + // this function will only be called to check for non-anonymous paths. + [tcx.crate_name(path.krate)] + .into_iter() + .chain(path.data.into_iter().map(|seg| seg.as_sym(/*verbose=*/ false))) + .zip(name.iter().map(|s| Symbol::intern(s))) + .all(|(sym, expected)| sym == expected) } /// Checks that `ty` has the same ABI as `rs_std::SliceRef`.
diff --git a/cc_bindings_from_rs/test/aliasing_references/BUILD b/cc_bindings_from_rs/test/aliasing_references/BUILD index ef3bfd9..3e5c232 100644 --- a/cc_bindings_from_rs/test/aliasing_references/BUILD +++ b/cc_bindings_from_rs/test/aliasing_references/BUILD
@@ -41,6 +41,6 @@ srcs = ["aliasing_references_test.cc"], deps = [ ":aliasing_references_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/aliasing_references/aliasing_references_cc_api.h b/cc_bindings_from_rs/test/aliasing_references/aliasing_references_cc_api.h index bd1158a..c151e6d 100644 --- a/cc_bindings_from_rs/test/aliasing_references/aliasing_references_cc_api.h +++ b/cc_bindings_from_rs/test/aliasing_references/aliasing_references_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // aliasing_references_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_ALIASING_REFERENCES_ALIASING_REFERENCES_GOLDEN
diff --git a/cc_bindings_from_rs/test/aliasing_references/aliasing_references_cc_api_impl.rs b/cc_bindings_from_rs/test/aliasing_references/aliasing_references_cc_api_impl.rs index 9a0e712..41fd346 100644 --- a/cc_bindings_from_rs/test/aliasing_references/aliasing_references_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/aliasing_references/aliasing_references_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // aliasing_references_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/arrays/BUILD b/cc_bindings_from_rs/test/arrays/BUILD index 0acae3a..3bba626 100644 --- a/cc_bindings_from_rs/test/arrays/BUILD +++ b/cc_bindings_from_rs/test/arrays/BUILD
@@ -41,6 +41,6 @@ srcs = ["arrays_test.cc"], deps = [ ":arrays_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/arrays/arrays.rs b/cc_bindings_from_rs/test/arrays/arrays.rs index 7989493..c9716bc 100644 --- a/cc_bindings_from_rs/test/arrays/arrays.rs +++ b/cc_bindings_from_rs/test/arrays/arrays.rs
@@ -8,15 +8,28 @@ pub fn function_with_const_array_ptr_id(array_ptr: *const [i32; 2]) -> *const [i32; 2] { array_ptr } -// TODO: b/260128806 - Support this use. + pub fn function_with_array_id(array: [i32; 2]) -> [i32; 2] { array } -// TODO: b/260128806 - Support this use. + pub fn function_with_array_tuple_id(array_tup: ([i32; 2], [i32; 2])) -> ([i32; 2], [i32; 2]) { array_tup } +// Will not generate a stub: tuple types cannot be used inside of compound data types, +// because std::tuple is not layout-compatible with a Rust tuple. +pub fn function_with_tuple_array_id(tup_array: [(i32, i32); 2]) -> [(i32, i32); 2] { + tup_array +} + +const NAMED_SIZE: usize = 3; +pub fn function_with_mut_array_named_size_ptr_id( + array_ptr: *const [i32; NAMED_SIZE], +) -> *const [i32; NAMED_SIZE] { + array_ptr +} + #[derive(Default, Clone, Copy)] pub struct ArrayStruct { pub array: [i32; 2], @@ -25,3 +38,56 @@ pub fn function_with_array_struct_id(array_struct: ArrayStruct) -> ArrayStruct { array_struct } + +pub struct HasDrop { + pub x: i32, +} + +impl HasDrop { + pub fn new(x: i32) -> HasDrop { + HasDrop { x } + } +} + +impl Drop for HasDrop { + fn drop(&mut self) {} +} + +pub fn function_with_has_drop_array_id(array: [HasDrop; 2]) -> [HasDrop; 2] { + dbg!(array[0].x); + dbg!(array[1].x); + array +} + +pub fn function_with_has_drop_ret_only() -> [HasDrop; 2] { + [HasDrop::new(1), HasDrop::new(2)] +} + +#[derive(Default)] +pub struct HasDropAndDefault { + pub x: i32, +} + +impl Drop for HasDropAndDefault { + fn drop(&mut self) {} +} + +pub fn function_with_has_drop_and_default_array_id( + array: [HasDropAndDefault; 2], +) -> [HasDropAndDefault; 2] { + array +} + +// TODO: b/260128806 - we conservatively reject nested arrays. +pub fn function_with_nested_arrays(array: [[i32; 2]; 2]) -> [[i32; 2]; 2] { + array +} + +// TODO: b/451981992 - we don't support nested arrays with types that are Drop but not Default. +pub fn function_with_nested_droponly_arrays(array: [[HasDrop; 2]; 2]) -> [[HasDrop; 2]; 2] { + array +} + +pub fn function_with_empty_array(array: [i32; 0]) -> [i32; 0] { + array +}
diff --git a/cc_bindings_from_rs/test/arrays/arrays_cc_api.h b/cc_bindings_from_rs/test/arrays/arrays_cc_api.h index 9fe76ce..5b39c7e 100644 --- a/cc_bindings_from_rs/test/arrays/arrays_cc_api.h +++ b/cc_bindings_from_rs/test/arrays/arrays_cc_api.h
@@ -4,18 +4,21 @@ // Automatically @generated C++ bindings for the following Rust crate: // arrays_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_ARRAYS_ARRAYS_GOLDEN #define THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_ARRAYS_ARRAYS_GOLDEN #include "support/annotations_internal.h" +#include "support/internal/memswap.h" #include "support/internal/slot.h" #include <array> #include <cstddef> #include <cstdint> +#include <tuple> #include <type_traits> #include <utility> @@ -26,16 +29,30 @@ std::array<std::int32_t, 2> const* function_with_const_array_ptr_id( std::array<std::int32_t, 2> const* array_ptr); -// Error generating bindings for `function_with_array_id` defined at -// cc_bindings_from_rs/test/arrays/arrays.rs;l=12: -// Unknown type - -// Error generating bindings for `function_with_array_tuple_id` defined at -// cc_bindings_from_rs/test/arrays/arrays.rs;l=16: -// Attempted to write out unknown type from Rust to C +// Generated from: +// cc_bindings_from_rs/test/arrays/arrays.rs;l=12 +std::array<std::int32_t, 2> function_with_array_id( + std::array<std::int32_t, 2> array); // Generated from: -// cc_bindings_from_rs/test/arrays/arrays.rs;l=21 +// cc_bindings_from_rs/test/arrays/arrays.rs;l=16 +std::tuple<std::array<std::int32_t, 2>, std::array<std::int32_t, 2>> +function_with_array_tuple_id( + std::tuple<std::array<std::int32_t, 2>, std::array<std::int32_t, 2>> + array_tup); + +// Error generating bindings for `function_with_tuple_array_id` defined at +// cc_bindings_from_rs/test/arrays/arrays.rs;l=22: +// Tuple types cannot be used inside of compound data types, because std::tuple +// is not layout-compatible with a Rust tuple. + +// Generated from: +// cc_bindings_from_rs/test/arrays/arrays.rs;l=27 +std::array<std::int32_t, 3> const* function_with_mut_array_named_size_ptr_id( + std::array<std::int32_t, 3> const* array_ptr); + +// Generated from: +// cc_bindings_from_rs/test/arrays/arrays.rs;l=34 struct CRUBIT_INTERNAL_RUST_TYPE(":: arrays_golden :: ArrayStruct") alignas(4) [[clang::trivial_abi]] ArrayStruct final { public: @@ -56,7 +73,7 @@ } union { // Generated from: - // cc_bindings_from_rs/test/arrays/arrays.rs;l=22 + // cc_bindings_from_rs/test/arrays/arrays.rs;l=35 std::array<std::int32_t, 2> array; }; @@ -65,10 +82,105 @@ }; // Generated from: -// cc_bindings_from_rs/test/arrays/arrays.rs;l=25 +// cc_bindings_from_rs/test/arrays/arrays.rs;l=38 ::arrays::ArrayStruct function_with_array_struct_id( ::arrays::ArrayStruct array_struct); +// Generated from: +// cc_bindings_from_rs/test/arrays/arrays.rs;l=42 +struct CRUBIT_INTERNAL_RUST_TYPE(":: arrays_golden :: HasDrop") alignas(4) + [[clang::trivial_abi]] HasDrop final { + public: + // `HasDrop` doesn't implement the `Default` trait + HasDrop() = delete; + + // Drop::drop + ~HasDrop(); + + // C++ moves are deleted because there's no non-destructive implementation + // available. + HasDrop(HasDrop&&) = delete; + HasDrop& operator=(HasDrop&&) = delete; + // `HasDrop` doesn't implement the `Clone` trait + HasDrop(const HasDrop&) = delete; + HasDrop& operator=(const HasDrop&) = delete; + HasDrop(::crubit::UnsafeRelocateTag, HasDrop&& value) { + memcpy(this, &value, sizeof(value)); + } + + // Generated from: + // cc_bindings_from_rs/test/arrays/arrays.rs;l=47 + static ::arrays::HasDrop new_(std::int32_t x); + + union { + // Generated from: + // cc_bindings_from_rs/test/arrays/arrays.rs;l=43 + std::int32_t x; + }; + + private: + static void __crubit_field_offset_assertions(); +}; + +// Generated from: +// cc_bindings_from_rs/test/arrays/arrays.rs;l=56 +std::array<::arrays::HasDrop, 2> function_with_has_drop_array_id( + std::array<::arrays::HasDrop, 2> array); + +// Generated from: +// cc_bindings_from_rs/test/arrays/arrays.rs;l=62 +std::array<::arrays::HasDrop, 2> function_with_has_drop_ret_only(); + +// Generated from: +// cc_bindings_from_rs/test/arrays/arrays.rs;l=67 +struct CRUBIT_INTERNAL_RUST_TYPE( + ":: arrays_golden :: HasDropAndDefault") alignas(4) [[clang::trivial_abi]] +HasDropAndDefault final { + public: + // Default::default + HasDropAndDefault(); + + // Drop::drop + ~HasDropAndDefault(); + + HasDropAndDefault(HasDropAndDefault&&); + HasDropAndDefault& operator=(HasDropAndDefault&&); + + // `HasDropAndDefault` doesn't implement the `Clone` trait + HasDropAndDefault(const HasDropAndDefault&) = delete; + HasDropAndDefault& operator=(const HasDropAndDefault&) = delete; + HasDropAndDefault(::crubit::UnsafeRelocateTag, HasDropAndDefault&& value) { + memcpy(this, &value, sizeof(value)); + } + union { + // Generated from: + // cc_bindings_from_rs/test/arrays/arrays.rs;l=68 + std::int32_t x; + }; + + private: + static void __crubit_field_offset_assertions(); +}; + +// Generated from: +// cc_bindings_from_rs/test/arrays/arrays.rs;l=75 +std::array<::arrays::HasDropAndDefault, 2> +function_with_has_drop_and_default_array_id( + std::array<::arrays::HasDropAndDefault, 2> array); + +// Error generating bindings for `function_with_nested_arrays` defined at +// cc_bindings_from_rs/test/arrays/arrays.rs;l=82: +// b/260128806 - nested array [i32; 2] is not supported + +// Error generating bindings for `function_with_nested_droponly_arrays` defined +// at cc_bindings_from_rs/test/arrays/arrays.rs;l=87: +// b/260128806 - nested array [HasDrop; 2] is not supported + +// Generated from: +// cc_bindings_from_rs/test/arrays/arrays.rs;l=91 +std::array<std::int32_t, 0> function_with_empty_array( + std::array<std::int32_t, 0> array); + namespace __crubit_internal { extern "C" std::array<std::int32_t, 2> const* __crubit_thunk_function_uwith_uconst_uarray_uptr_uid( @@ -80,6 +192,58 @@ __crubit_thunk_function_uwith_uconst_uarray_uptr_uid(array_ptr); } +namespace __crubit_internal { +extern "C" void __crubit_thunk_function_uwith_uarray_uid(void*, + void* __ret_ptr); +} +inline std::array<std::int32_t, 2> function_with_array_id( + std::array<std::int32_t, 2> array) { + crubit::Slot<std::array<std::int32_t, 2>> __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_function_uwith_uarray_uid( + &array, __return_value_storage); + return std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + +namespace __crubit_internal { +extern "C" void __crubit_thunk_function_uwith_uarray_utuple_uid( + void**, void** __ret_ptr); +} +inline std::tuple<std::array<std::int32_t, 2>, std::array<std::int32_t, 2>> +function_with_array_tuple_id( + std::tuple<std::array<std::int32_t, 2>, std::array<std::int32_t, 2>> + array_tup) { + auto&& array_tup_0 = std::get<0>(array_tup); + auto&& array_tup_cabi_0 = &array_tup_0; + auto&& array_tup_1 = std::get<1>(array_tup); + auto&& array_tup_cabi_1 = &array_tup_1; + void* array_tup_cabi[] = {&array_tup_cabi_0, &array_tup_cabi_1}; + crubit::Slot<std::array<std::int32_t, 2>> __return_value_0_ret_val_holder; + auto* __return_value_0_storage = __return_value_0_ret_val_holder.Get(); + crubit::Slot<std::array<std::int32_t, 2>> __return_value_1_ret_val_holder; + auto* __return_value_1_storage = __return_value_1_ret_val_holder.Get(); + void* __return_value_storage[] = {__return_value_0_storage, + __return_value_1_storage}; + __crubit_internal::__crubit_thunk_function_uwith_uarray_utuple_uid( + array_tup_cabi, __return_value_storage); + return std::make_tuple( + std::move(__return_value_0_ret_val_holder).AssumeInitAndTakeValue(), + std::move(__return_value_1_ret_val_holder).AssumeInitAndTakeValue()); +} + +namespace __crubit_internal { +extern "C" std::array<std::int32_t, 3> const* +__crubit_thunk_function_uwith_umut_uarray_unamed_usize_uptr_uid( + std::array<std::int32_t, 3> const*); +} +inline std::array<std::int32_t, 3> const* +function_with_mut_array_named_size_ptr_id( + std::array<std::int32_t, 3> const* array_ptr) { + return __crubit_internal:: + __crubit_thunk_function_uwith_umut_uarray_unamed_usize_uptr_uid( + array_ptr); +} + static_assert( sizeof(ArrayStruct) == 8, "Verify that ADT layout didn't change since this header got generated"); @@ -113,5 +277,114 @@ return std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); } +static_assert( + sizeof(HasDrop) == 4, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(HasDrop) == 4, + "Verify that ADT layout didn't change since this header got generated"); +namespace __crubit_internal { +extern "C" void __crubit_thunk_drop(::arrays::HasDrop&); +} +inline HasDrop::~HasDrop() { __crubit_internal::__crubit_thunk_drop(*this); } +namespace __crubit_internal { +extern "C" void __crubit_thunk_new(std::int32_t, ::arrays::HasDrop* __ret_ptr); +} +inline ::arrays::HasDrop HasDrop::new_(std::int32_t x) { + crubit::Slot<::arrays::HasDrop> __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_new(x, __return_value_storage); + return std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} +inline void HasDrop::__crubit_field_offset_assertions() { + static_assert(0 == offsetof(HasDrop, x)); +} +namespace __crubit_internal { +extern "C" void __crubit_thunk_function_uwith_uhas_udrop_uarray_uid( + void*, void* __ret_ptr); +} +inline std::array<::arrays::HasDrop, 2> function_with_has_drop_array_id( + std::array<::arrays::HasDrop, 2> array) { + crubit::Slot array_slot((std::move(array))); + crubit::Slot<std::array<::arrays::HasDrop, 2>> __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_function_uwith_uhas_udrop_uarray_uid( + array_slot.Get(), __return_value_storage); + return std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + +namespace __crubit_internal { +extern "C" void __crubit_thunk_function_uwith_uhas_udrop_uret_uonly( + void* __ret_ptr); +} +inline std::array<::arrays::HasDrop, 2> function_with_has_drop_ret_only() { + crubit::Slot<std::array<::arrays::HasDrop, 2>> __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_function_uwith_uhas_udrop_uret_uonly( + __return_value_storage); + return std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + +static_assert( + sizeof(HasDropAndDefault) == 4, + "Verify that ADT layout didn't change since this header got generated"); +static_assert( + alignof(HasDropAndDefault) == 4, + "Verify that ADT layout didn't change since this header got generated"); +namespace __crubit_internal { +extern "C" void __crubit_thunk_default(::arrays::HasDropAndDefault* __ret_ptr); +} +inline HasDropAndDefault::HasDropAndDefault() { + __crubit_internal::__crubit_thunk_default(this); +} +namespace __crubit_internal { +extern "C" void __crubit_thunk_drop(::arrays::HasDropAndDefault&); +} +inline HasDropAndDefault::~HasDropAndDefault() { + __crubit_internal::__crubit_thunk_drop(*this); +} +inline HasDropAndDefault::HasDropAndDefault(HasDropAndDefault&& other) + : HasDropAndDefault() { + *this = std::move(other); +} +inline HasDropAndDefault& HasDropAndDefault::operator=( + HasDropAndDefault&& other) { + crubit::MemSwap(*this, other); + return *this; +} +inline void HasDropAndDefault::__crubit_field_offset_assertions() { + static_assert(0 == offsetof(HasDropAndDefault, x)); +} +namespace __crubit_internal { +extern "C" void +__crubit_thunk_function_uwith_uhas_udrop_uand_udefault_uarray_uid( + void*, void* __ret_ptr); +} +inline std::array<::arrays::HasDropAndDefault, 2> +function_with_has_drop_and_default_array_id( + std::array<::arrays::HasDropAndDefault, 2> array) { + crubit::Slot array_slot((std::move(array))); + crubit::Slot<std::array<::arrays::HasDropAndDefault, 2>> + __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal:: + __crubit_thunk_function_uwith_uhas_udrop_uand_udefault_uarray_uid( + array_slot.Get(), __return_value_storage); + return std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + +namespace __crubit_internal { +extern "C" void __crubit_thunk_function_uwith_uempty_uarray(void*, + void* __ret_ptr); +} +inline std::array<std::int32_t, 0> function_with_empty_array( + std::array<std::int32_t, 0> array) { + crubit::Slot<std::array<std::int32_t, 0>> __return_value_ret_val_holder; + auto* __return_value_storage = __return_value_ret_val_holder.Get(); + __crubit_internal::__crubit_thunk_function_uwith_uempty_uarray( + &array, __return_value_storage); + return std::move(__return_value_ret_val_holder).AssumeInitAndTakeValue(); +} + } // namespace arrays #endif // THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_ARRAYS_ARRAYS_GOLDEN
diff --git a/cc_bindings_from_rs/test/arrays/arrays_cc_api_impl.rs b/cc_bindings_from_rs/test/arrays/arrays_cc_api_impl.rs index 629650a..b1bfa10 100644 --- a/cc_bindings_from_rs/test/arrays/arrays_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/arrays/arrays_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // arrays_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)] @@ -16,6 +16,54 @@ ) -> *const [i32; 2] { unsafe { ::arrays_golden::function_with_const_array_ptr_id(array_ptr) } } +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_function_uwith_uarray_uid( + array: &'static mut ::core::mem::MaybeUninit<[i32; 2]>, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let array = array.assume_init_read(); + let __rs_return_value = ::arrays_golden::function_with_array_id(array); + (__ret_ptr as *mut [i32; 2]).write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_function_uwith_uarray_utuple_uid( + array_tup: *const [*const core::ffi::c_void; 2usize], + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let array_tup = ( + { + let array_tup_0: &'static mut ::core::mem::MaybeUninit<[i32; 2]> = ((*array_tup) + [0usize] + as *const &'static mut ::core::mem::MaybeUninit<[i32; 2]>) + .read(); + let array_tup_0 = array_tup_0.assume_init_read(); + array_tup_0 + }, + { + let array_tup_1: &'static mut ::core::mem::MaybeUninit<[i32; 2]> = ((*array_tup) + [1usize] + as *const &'static mut ::core::mem::MaybeUninit<[i32; 2]>) + .read(); + let array_tup_1 = array_tup_1.assume_init_read(); + array_tup_1 + }, + ); + let __rs_return_value = ::arrays_golden::function_with_array_tuple_id(array_tup); + let (__rs_return_value_0, __rs_return_value_1) = __rs_return_value; + let [__ret_ptr_0, __ret_ptr_1] = *(__ret_ptr as *mut [*mut core::ffi::c_void; 2usize]); + (__ret_ptr_0 as *mut [i32; 2]).write(__rs_return_value_0); + (__ret_ptr_1 as *mut [i32; 2]).write(__rs_return_value_1); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_function_uwith_umut_uarray_unamed_usize_uptr_uid( + array_ptr: *const [i32; 3], +) -> *const [i32; 3] { + unsafe { ::arrays_golden::function_with_mut_array_named_size_ptr_id(array_ptr) } +} const _: () = assert!(::std::mem::size_of::<::arrays_golden::ArrayStruct>() == 8); const _: () = assert!(::std::mem::align_of::<::arrays_golden::ArrayStruct>() == 4); #[unsafe(no_mangle)] @@ -38,3 +86,78 @@ (__ret_ptr as *mut ::arrays_golden::ArrayStruct).write(__rs_return_value); } } +const _: () = assert!(::std::mem::size_of::<::arrays_golden::HasDrop>() == 4); +const _: () = assert!(::std::mem::align_of::<::arrays_golden::HasDrop>() == 4); +#[unsafe(no_mangle)] +extern "C" fn __crubit_thunk_drop( + __self: &'static mut ::core::mem::MaybeUninit<::arrays_golden::HasDrop>, +) { + unsafe { __self.assume_init_drop() }; +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_new(x: i32, __ret_ptr: *mut core::ffi::c_void) -> () { + unsafe { + let __rs_return_value = ::arrays_golden::HasDrop::new(x); + (__ret_ptr as *mut ::arrays_golden::HasDrop).write(__rs_return_value); + } +} +const _: () = assert!(::core::mem::offset_of!(::arrays_golden::HasDrop, x) == 0); +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_function_uwith_uhas_udrop_uarray_uid( + array: &'static mut ::core::mem::MaybeUninit<[::arrays_golden::HasDrop; 2]>, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let array = array.assume_init_read(); + let __rs_return_value = ::arrays_golden::function_with_has_drop_array_id(array); + (__ret_ptr as *mut [::arrays_golden::HasDrop; 2]).write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_function_uwith_uhas_udrop_uret_uonly( + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let __rs_return_value = ::arrays_golden::function_with_has_drop_ret_only(); + (__ret_ptr as *mut [::arrays_golden::HasDrop; 2]).write(__rs_return_value); + } +} +const _: () = assert!(::std::mem::size_of::<::arrays_golden::HasDropAndDefault>() == 4); +const _: () = assert!(::std::mem::align_of::<::arrays_golden::HasDropAndDefault>() == 4); +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_default(__ret_ptr: *mut core::ffi::c_void) -> () { + unsafe { + let __rs_return_value = + <::arrays_golden::HasDropAndDefault as ::core::default::Default>::default(); + (__ret_ptr as *mut ::arrays_golden::HasDropAndDefault).write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +extern "C" fn __crubit_thunk_drop( + __self: &'static mut ::core::mem::MaybeUninit<::arrays_golden::HasDropAndDefault>, +) { + unsafe { __self.assume_init_drop() }; +} +const _: () = assert!(::core::mem::offset_of!(::arrays_golden::HasDropAndDefault, x) == 0); +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_function_uwith_uhas_udrop_uand_udefault_uarray_uid( + array: &'static mut ::core::mem::MaybeUninit<[::arrays_golden::HasDropAndDefault; 2]>, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let array = array.assume_init_read(); + let __rs_return_value = ::arrays_golden::function_with_has_drop_and_default_array_id(array); + (__ret_ptr as *mut [::arrays_golden::HasDropAndDefault; 2]).write(__rs_return_value); + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_function_uwith_uempty_uarray( + array: &'static mut ::core::mem::MaybeUninit<[i32; 0]>, + __ret_ptr: *mut core::ffi::c_void, +) -> () { + unsafe { + let array = array.assume_init_read(); + let __rs_return_value = ::arrays_golden::function_with_empty_array(array); + (__ret_ptr as *mut [i32; 0]).write(__rs_return_value); + } +}
diff --git a/cc_bindings_from_rs/test/arrays/arrays_test.cc b/cc_bindings_from_rs/test/arrays/arrays_test.cc index 7f3580d..81644fe 100644 --- a/cc_bindings_from_rs/test/arrays/arrays_test.cc +++ b/cc_bindings_from_rs/test/arrays/arrays_test.cc
@@ -23,4 +23,46 @@ array_struct.array); } +TEST(ArraysTest, ArrayValueInOut) { + std::array<int32_t, 2> array = {1, 2}; + EXPECT_EQ(arrays::function_with_array_id(array), array); +} + +TEST(ArraysTest, TupleOfArraysValueInOut) { + std::tuple<std::array<int32_t, 2>, std::array<int32_t, 2>> array_tup{{1, 2}, + {3, 4}}; + EXPECT_EQ(arrays::function_with_array_tuple_id(array_tup), array_tup); +} + +TEST(ArraysTest, DropOut) { + auto out = arrays::function_with_has_drop_ret_only(); + EXPECT_EQ(out[0].x, 1); + EXPECT_EQ(out[1].x, 2); +} + +TEST(ArraysTest, DropInOut) { + auto out = arrays::function_with_has_drop_array_id( + {arrays::HasDrop::new_(1), arrays::HasDrop::new_(2)}); + EXPECT_EQ(out[0].x, 1); + EXPECT_EQ(out[1].x, 2); +} + +TEST(ArraysTest, DropAndDefaultInOut) { + arrays::HasDropAndDefault a; + arrays::HasDropAndDefault b; + a.x = 1; + b.x = 2; + std::array<arrays::HasDropAndDefault, 2> array{std::move(a), std::move(b)}; + EXPECT_EQ(array[0].x, 1); + EXPECT_EQ(array[1].x, 2); + auto out = + arrays::function_with_has_drop_and_default_array_id(std::move(array)); + EXPECT_EQ(out[0].x, 1); + EXPECT_EQ(out[1].x, 2); +} + +TEST(ArraysTest, EmptyArrayInOut) { + std::array<int32_t, 0> array; + EXPECT_EQ(arrays::function_with_empty_array(array), array); +} } // namespace
diff --git a/cc_bindings_from_rs/test/attribute/BUILD b/cc_bindings_from_rs/test/attribute/BUILD index caefda2..dd9c800 100644 --- a/cc_bindings_from_rs/test/attribute/BUILD +++ b/cc_bindings_from_rs/test/attribute/BUILD
@@ -43,7 +43,7 @@ srcs = ["cpp_name_test.cc"], deps = [ ":cpp_name_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -73,6 +73,6 @@ srcs = ["must_bind_test.cc"], deps = [ ":must_bind_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/attribute/cpp_name_cc_api.h b/cc_bindings_from_rs/test/attribute/cpp_name_cc_api.h index 68281a0..c698310 100644 --- a/cc_bindings_from_rs/test/attribute/cpp_name_cc_api.h +++ b/cc_bindings_from_rs/test/attribute/cpp_name_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // cpp_name_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_ATTRIBUTE_CPP_NAME_GOLDEN
diff --git a/cc_bindings_from_rs/test/attribute/cpp_name_cc_api_impl.rs b/cc_bindings_from_rs/test/attribute/cpp_name_cc_api_impl.rs index d0e5f3a..899b32a 100644 --- a/cc_bindings_from_rs/test/attribute/cpp_name_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/attribute/cpp_name_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // cpp_name_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/attribute/must_bind_cc_api.h b/cc_bindings_from_rs/test/attribute/must_bind_cc_api.h index a86bab5..20ae3d0 100644 --- a/cc_bindings_from_rs/test/attribute/must_bind_cc_api.h +++ b/cc_bindings_from_rs/test/attribute/must_bind_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // must_bind_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_ATTRIBUTE_MUST_BIND_GOLDEN
diff --git a/cc_bindings_from_rs/test/attribute/must_bind_cc_api_impl.rs b/cc_bindings_from_rs/test/attribute/must_bind_cc_api_impl.rs index dd6008f..c189f93 100644 --- a/cc_bindings_from_rs/test/attribute/must_bind_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/attribute/must_bind_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // must_bind_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/bazel/build_rs/BUILD b/cc_bindings_from_rs/test/bazel/build_rs/BUILD index 15f1bcc..7428284 100644 --- a/cc_bindings_from_rs/test/bazel/build_rs/BUILD +++ b/cc_bindings_from_rs/test/bazel/build_rs/BUILD
@@ -32,6 +32,6 @@ srcs = ["build_rs_test.cc"], deps = [ ":build_rs_user_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/bazel/crate_features/BUILD b/cc_bindings_from_rs/test/bazel/crate_features/BUILD index 8f45fba..a8839f6 100644 --- a/cc_bindings_from_rs/test/bazel/crate_features/BUILD +++ b/cc_bindings_from_rs/test/bazel/crate_features/BUILD
@@ -30,6 +30,6 @@ srcs = ["needs_feature_test.cc"], deps = [ ":needs_feature_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/bazel/crate_flags/BUILD b/cc_bindings_from_rs/test/bazel/crate_flags/BUILD index 8e36beb..49c6106 100644 --- a/cc_bindings_from_rs/test/bazel/crate_flags/BUILD +++ b/cc_bindings_from_rs/test/bazel/crate_flags/BUILD
@@ -34,6 +34,6 @@ srcs = ["crate_flags_test.cc"], deps = [ ":crate_flags_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/bazel/crate_name/BUILD b/cc_bindings_from_rs/test/bazel/crate_name/BUILD index 2d519cb..a82de1e 100644 --- a/cc_bindings_from_rs/test/bazel/crate_name/BUILD +++ b/cc_bindings_from_rs/test/bazel/crate_name/BUILD
@@ -29,6 +29,6 @@ srcs = ["crate_name_test.cc"], deps = [ ":custom_crate_name_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/bazel/cross_crate/BUILD b/cc_bindings_from_rs/test/bazel/cross_crate/BUILD index 505c388..03bb367 100644 --- a/cc_bindings_from_rs/test/bazel/cross_crate/BUILD +++ b/cc_bindings_from_rs/test/bazel/cross_crate/BUILD
@@ -35,6 +35,6 @@ srcs = ["cross_crate_test.cc"], deps = [ ":test_api_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/bazel/env/BUILD b/cc_bindings_from_rs/test/bazel/env/BUILD index 30c260b..da788ac 100644 --- a/cc_bindings_from_rs/test/bazel/env/BUILD +++ b/cc_bindings_from_rs/test/bazel/env/BUILD
@@ -27,6 +27,6 @@ srcs = ["env_test.cc"], deps = [ ":env_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/bazel/include_str/BUILD b/cc_bindings_from_rs/test/bazel/include_str/BUILD index 7001c76..974c654 100644 --- a/cc_bindings_from_rs/test/bazel/include_str/BUILD +++ b/cc_bindings_from_rs/test/bazel/include_str/BUILD
@@ -30,6 +30,6 @@ srcs = ["include_str_test.cc"], deps = [ ":include_str_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/bridging/BUILD b/cc_bindings_from_rs/test/bridging/BUILD index 60ef556..c41a9d7 100644 --- a/cc_bindings_from_rs/test/bridging/BUILD +++ b/cc_bindings_from_rs/test/bridging/BUILD
@@ -58,6 +58,6 @@ deps = [ ":rust_pointer_types_cc_api", ":rust_type_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/bridging/composable/BUILD b/cc_bindings_from_rs/test/bridging/composable/BUILD index c78f03b..e6afd6c 100644 --- a/cc_bindings_from_rs/test/bridging/composable/BUILD +++ b/cc_bindings_from_rs/test/bridging/composable/BUILD
@@ -55,6 +55,6 @@ deps = [ ":composable_bridging_cc_api", "//support/rs_std:slice_ref", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/bridging/protobuf/BUILD b/cc_bindings_from_rs/test/bridging/protobuf/BUILD index 06be4a7..ee148d4 100644 --- a/cc_bindings_from_rs/test/bridging/protobuf/BUILD +++ b/cc_bindings_from_rs/test/bridging/protobuf/BUILD
@@ -64,6 +64,6 @@ deps = [ ":foo_cc_proto", ":rust_lib_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/bridging/protobuf/rust_lib_cc_api.h b/cc_bindings_from_rs/test/bridging/protobuf/rust_lib_cc_api.h index 4a4b254..10f0957 100644 --- a/cc_bindings_from_rs/test/bridging/protobuf/rust_lib_cc_api.h +++ b/cc_bindings_from_rs/test/bridging/protobuf/rust_lib_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // rust_lib_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_BRIDGING_PROTOBUF_RUST_LIB_GOLDEN
diff --git a/cc_bindings_from_rs/test/bridging/protobuf/rust_lib_cc_api_impl.rs b/cc_bindings_from_rs/test/bridging/protobuf/rust_lib_cc_api_impl.rs index 6c7e25b..56d7930 100644 --- a/cc_bindings_from_rs/test/bridging/protobuf/rust_lib_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/bridging/protobuf/rust_lib_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // rust_lib_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/bridging/string/BUILD b/cc_bindings_from_rs/test/bridging/string/BUILD index 8346ec5..d949374 100644 --- a/cc_bindings_from_rs/test/bridging/string/BUILD +++ b/cc_bindings_from_rs/test/bridging/string/BUILD
@@ -30,6 +30,6 @@ srcs = ["string_test.cc"], deps = [ ":string_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/consts/BUILD b/cc_bindings_from_rs/test/consts/BUILD index 7e1a559..73725ee 100644 --- a/cc_bindings_from_rs/test/consts/BUILD +++ b/cc_bindings_from_rs/test/consts/BUILD
@@ -48,6 +48,6 @@ srcs = ["consts_test.cc"], deps = [ ":consts_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/enums/BUILD b/cc_bindings_from_rs/test/enums/BUILD index 54aef16..0fbe9a6 100644 --- a/cc_bindings_from_rs/test/enums/BUILD +++ b/cc_bindings_from_rs/test/enums/BUILD
@@ -48,7 +48,7 @@ srcs = ["enums_test.cc"], deps = [ ":enums_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -79,6 +79,6 @@ srcs = ["cpp_enums_test.cc"], deps = [ ":cpp_enums_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/enums/cpp_enums_cc_api.h b/cc_bindings_from_rs/test/enums/cpp_enums_cc_api.h index 08ee44e..c2ef80e 100644 --- a/cc_bindings_from_rs/test/enums/cpp_enums_cc_api.h +++ b/cc_bindings_from_rs/test/enums/cpp_enums_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // cpp_enums_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_ENUMS_CPP_ENUMS_GOLDEN
diff --git a/cc_bindings_from_rs/test/experimental_unions/BUILD b/cc_bindings_from_rs/test/experimental_unions/BUILD index 55d3ea8..fa67ada 100644 --- a/cc_bindings_from_rs/test/experimental_unions/BUILD +++ b/cc_bindings_from_rs/test/experimental_unions/BUILD
@@ -33,6 +33,6 @@ srcs = ["unions_test.cc"], deps = [ ":unions_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/function_pointers/BUILD b/cc_bindings_from_rs/test/function_pointers/BUILD index c79c049..f711988 100644 --- a/cc_bindings_from_rs/test/function_pointers/BUILD +++ b/cc_bindings_from_rs/test/function_pointers/BUILD
@@ -42,6 +42,6 @@ srcs = ["function_pointers_test.cc"], deps = [ ":function_pointers_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/functions/BUILD b/cc_bindings_from_rs/test/functions/BUILD index 08a0ffb..444e4f0 100644 --- a/cc_bindings_from_rs/test/functions/BUILD +++ b/cc_bindings_from_rs/test/functions/BUILD
@@ -34,6 +34,6 @@ deps = [ ":functions_cc_api", "//support/rs_std:char", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/impls/BUILD b/cc_bindings_from_rs/test/impls/BUILD index ae1503a..421dd7c 100644 --- a/cc_bindings_from_rs/test/impls/BUILD +++ b/cc_bindings_from_rs/test/impls/BUILD
@@ -36,6 +36,6 @@ srcs = ["impls_test.cc"], deps = [ ":impls_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/known_traits/clone/BUILD b/cc_bindings_from_rs/test/known_traits/clone/BUILD index fed90b0..4e40f9d 100644 --- a/cc_bindings_from_rs/test/known_traits/clone/BUILD +++ b/cc_bindings_from_rs/test/known_traits/clone/BUILD
@@ -33,6 +33,6 @@ srcs = ["clone_test.cc"], deps = [ ":rs_clone_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/known_traits/copy/BUILD b/cc_bindings_from_rs/test/known_traits/copy/BUILD index 4e25d8f..105945b 100644 --- a/cc_bindings_from_rs/test/known_traits/copy/BUILD +++ b/cc_bindings_from_rs/test/known_traits/copy/BUILD
@@ -31,6 +31,6 @@ srcs = ["copy_test.cc"], deps = [ ":copy_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/known_traits/default/BUILD b/cc_bindings_from_rs/test/known_traits/default/BUILD index 7f088c5..1cd94fd 100644 --- a/cc_bindings_from_rs/test/known_traits/default/BUILD +++ b/cc_bindings_from_rs/test/known_traits/default/BUILD
@@ -30,6 +30,6 @@ srcs = ["default_test.cc"], deps = [ ":rs_default_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/known_traits/drop/BUILD b/cc_bindings_from_rs/test/known_traits/drop/BUILD index 57e88ac..46b8be2 100644 --- a/cc_bindings_from_rs/test/known_traits/drop/BUILD +++ b/cc_bindings_from_rs/test/known_traits/drop/BUILD
@@ -31,6 +31,6 @@ srcs = ["drop_test.cc"], deps = [ ":drop_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/known_traits/from/BUILD b/cc_bindings_from_rs/test/known_traits/from/BUILD index d807c3c..4ccfd5f 100644 --- a/cc_bindings_from_rs/test/known_traits/from/BUILD +++ b/cc_bindings_from_rs/test/known_traits/from/BUILD
@@ -47,6 +47,6 @@ srcs = ["from_test.cc"], deps = [ ":from_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/known_traits/from/from_cc_api.h b/cc_bindings_from_rs/test/known_traits/from/from_cc_api.h index 9d62c40..04db24f 100644 --- a/cc_bindings_from_rs/test/known_traits/from/from_cc_api.h +++ b/cc_bindings_from_rs/test/known_traits/from/from_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // from_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_KNOWN_TRAITS_FROM_FROM_GOLDEN
diff --git a/cc_bindings_from_rs/test/known_traits/from/from_cc_api_impl.rs b/cc_bindings_from_rs/test/known_traits/from/from_cc_api_impl.rs index 9c5c53a..63f7d75 100644 --- a/cc_bindings_from_rs/test/known_traits/from/from_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/known_traits/from/from_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // from_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/known_traits/into/BUILD b/cc_bindings_from_rs/test/known_traits/into/BUILD index 1d356ea..aa58641 100644 --- a/cc_bindings_from_rs/test/known_traits/into/BUILD +++ b/cc_bindings_from_rs/test/known_traits/into/BUILD
@@ -47,6 +47,6 @@ srcs = ["into_test.cc"], deps = [ ":into_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/known_traits/into/into_cc_api.h b/cc_bindings_from_rs/test/known_traits/into/into_cc_api.h index 3390b65..a6b2059 100644 --- a/cc_bindings_from_rs/test/known_traits/into/into_cc_api.h +++ b/cc_bindings_from_rs/test/known_traits/into/into_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // into_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_KNOWN_TRAITS_INTO_INTO_GOLDEN
diff --git a/cc_bindings_from_rs/test/known_traits/into/into_cc_api_impl.rs b/cc_bindings_from_rs/test/known_traits/into/into_cc_api_impl.rs index 7821464..e8477d8 100644 --- a/cc_bindings_from_rs/test/known_traits/into/into_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/known_traits/into/into_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // into_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/library_config_aspect_hint/BUILD b/cc_bindings_from_rs/test/library_config_aspect_hint/BUILD index 0a8ee88..742ba7c 100644 --- a/cc_bindings_from_rs/test/library_config_aspect_hint/BUILD +++ b/cc_bindings_from_rs/test/library_config_aspect_hint/BUILD
@@ -58,6 +58,6 @@ srcs = ["namespace_test.cc"], deps = [ ":namespace_crate2_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/lifetimes/BUILD b/cc_bindings_from_rs/test/lifetimes/BUILD index d175fc8..9c4f831 100644 --- a/cc_bindings_from_rs/test/lifetimes/BUILD +++ b/cc_bindings_from_rs/test/lifetimes/BUILD
@@ -41,6 +41,6 @@ srcs = ["lifetimes_test.cc"], deps = [ ":lifetimes_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/lifetimes/lifetimes_cc_api.h b/cc_bindings_from_rs/test/lifetimes/lifetimes_cc_api.h index ca54237..cc2ff70 100644 --- a/cc_bindings_from_rs/test/lifetimes/lifetimes_cc_api.h +++ b/cc_bindings_from_rs/test/lifetimes/lifetimes_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // lifetimes_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_LIFETIMES_LIFETIMES_GOLDEN
diff --git a/cc_bindings_from_rs/test/lifetimes/lifetimes_cc_api_impl.rs b/cc_bindings_from_rs/test/lifetimes/lifetimes_cc_api_impl.rs index 5525a6c..c5c6e99 100644 --- a/cc_bindings_from_rs/test/lifetimes/lifetimes_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/lifetimes/lifetimes_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // lifetimes_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/modules/BUILD b/cc_bindings_from_rs/test/modules/BUILD index 0985967..b67683c 100644 --- a/cc_bindings_from_rs/test/modules/BUILD +++ b/cc_bindings_from_rs/test/modules/BUILD
@@ -42,6 +42,6 @@ srcs = ["modules_test.cc"], deps = [ ":modules_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/modules/modules_cc_api.h b/cc_bindings_from_rs/test/modules/modules_cc_api.h index 184ae50..0e3019e 100644 --- a/cc_bindings_from_rs/test/modules/modules_cc_api.h +++ b/cc_bindings_from_rs/test/modules/modules_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // modules_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_MODULES_MODULES_GOLDEN
diff --git a/cc_bindings_from_rs/test/modules/modules_cc_api_impl.rs b/cc_bindings_from_rs/test/modules/modules_cc_api_impl.rs index d5e8bf7..bf3b627 100644 --- a/cc_bindings_from_rs/test/modules/modules_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/modules/modules_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // modules_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/move_semantics/BUILD b/cc_bindings_from_rs/test/move_semantics/BUILD index 6d2c8ac..d89bf0c 100644 --- a/cc_bindings_from_rs/test/move_semantics/BUILD +++ b/cc_bindings_from_rs/test/move_semantics/BUILD
@@ -39,6 +39,6 @@ srcs = ["move_test.cc"], deps = [ ":move_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/move_semantics/move_cc_api.h b/cc_bindings_from_rs/test/move_semantics/move_cc_api.h index 749485b..0788e8c 100644 --- a/cc_bindings_from_rs/test/move_semantics/move_cc_api.h +++ b/cc_bindings_from_rs/test/move_semantics/move_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // move_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_MOVE_SEMANTICS_MOVE_GOLDEN
diff --git a/cc_bindings_from_rs/test/move_semantics/move_cc_api_impl.rs b/cc_bindings_from_rs/test/move_semantics/move_cc_api_impl.rs index 306dd1c..ba6dedf 100644 --- a/cc_bindings_from_rs/test/move_semantics/move_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/move_semantics/move_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // move_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/never/BUILD b/cc_bindings_from_rs/test/never/BUILD index 253cf36..30eecd8 100644 --- a/cc_bindings_from_rs/test/never/BUILD +++ b/cc_bindings_from_rs/test/never/BUILD
@@ -38,6 +38,6 @@ srcs = ["never_test.cc"], deps = [ ":never_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/never/never_cc_api.h b/cc_bindings_from_rs/test/never/never_cc_api.h index 7b4c218..7130d5d 100644 --- a/cc_bindings_from_rs/test/never/never_cc_api.h +++ b/cc_bindings_from_rs/test/never/never_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // never_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_NEVER_NEVER_GOLDEN
diff --git a/cc_bindings_from_rs/test/never/never_cc_api_impl.rs b/cc_bindings_from_rs/test/never/never_cc_api_impl.rs index 0fc8525..503ccd0 100644 --- a/cc_bindings_from_rs/test/never/never_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/never/never_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // never_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/non_local_crate_bindings/BUILD b/cc_bindings_from_rs/test/non_local_crate_bindings/BUILD index 84a1901..6823e78 100644 --- a/cc_bindings_from_rs/test/non_local_crate_bindings/BUILD +++ b/cc_bindings_from_rs/test/non_local_crate_bindings/BUILD
@@ -38,6 +38,6 @@ srcs = ["core_bindings_test.cc"], deps = [ ":core_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/primitive_types/BUILD b/cc_bindings_from_rs/test/primitive_types/BUILD index eadc51a..6dc82f6 100644 --- a/cc_bindings_from_rs/test/primitive_types/BUILD +++ b/cc_bindings_from_rs/test/primitive_types/BUILD
@@ -17,7 +17,7 @@ aspect_hints = [ "//features:experimental", ], - deps = ["@crate_index//:libc"], + deps = ["@crate_index//:libc"], # v0_2 ) cc_bindings_from_rust( @@ -31,6 +31,6 @@ srcs = ["primitive_types_test.cc"], deps = [ ":primitive_types_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/str/BUILD b/cc_bindings_from_rs/test/str/BUILD index 42094db..0cc69ed 100644 --- a/cc_bindings_from_rs/test/str/BUILD +++ b/cc_bindings_from_rs/test/str/BUILD
@@ -38,6 +38,6 @@ srcs = ["str_test.cc"], deps = [ ":str_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/str/str_cc_api.h b/cc_bindings_from_rs/test/str/str_cc_api.h index 51d8273..24e5bb7 100644 --- a/cc_bindings_from_rs/test/str/str_cc_api.h +++ b/cc_bindings_from_rs/test/str/str_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // str_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_STR_STR_GOLDEN
diff --git a/cc_bindings_from_rs/test/str/str_cc_api_impl.rs b/cc_bindings_from_rs/test/str/str_cc_api_impl.rs index dfcf3b3..bca4ad3 100644 --- a/cc_bindings_from_rs/test/str/str_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/str/str_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // str_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/structs/BUILD b/cc_bindings_from_rs/test/structs/BUILD index 8a14be2..b5c2385 100644 --- a/cc_bindings_from_rs/test/structs/BUILD +++ b/cc_bindings_from_rs/test/structs/BUILD
@@ -47,6 +47,6 @@ srcs = ["structs_test.cc"], deps = [ ":structs_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/structs/structs_cc_api.h b/cc_bindings_from_rs/test/structs/structs_cc_api.h index 8784a1c..770d29f 100644 --- a/cc_bindings_from_rs/test/structs/structs_cc_api.h +++ b/cc_bindings_from_rs/test/structs/structs_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // structs_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_STRUCTS_STRUCTS_GOLDEN
diff --git a/cc_bindings_from_rs/test/structs/structs_cc_api_impl.rs b/cc_bindings_from_rs/test/structs/structs_cc_api_impl.rs index 86855ee..ab370f7 100644 --- a/cc_bindings_from_rs/test/structs/structs_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/structs/structs_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // structs_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/structs/tuple_structs/BUILD b/cc_bindings_from_rs/test/structs/tuple_structs/BUILD index 4adefcf..9557f31 100644 --- a/cc_bindings_from_rs/test/structs/tuple_structs/BUILD +++ b/cc_bindings_from_rs/test/structs/tuple_structs/BUILD
@@ -50,6 +50,6 @@ srcs = ["tuple_structs_test.cc"], deps = [ ":tuple_structs_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/structs/tuple_structs/tuple_structs_cc_api.h b/cc_bindings_from_rs/test/structs/tuple_structs/tuple_structs_cc_api.h index d31e536..389426e 100644 --- a/cc_bindings_from_rs/test/structs/tuple_structs/tuple_structs_cc_api.h +++ b/cc_bindings_from_rs/test/structs/tuple_structs/tuple_structs_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // tuple_structs_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_STRUCTS_TUPLE_STRUCTS_TUPLE_STRUCTS_GOLDEN
diff --git a/cc_bindings_from_rs/test/structs/tuple_structs/tuple_structs_cc_api_impl.rs b/cc_bindings_from_rs/test/structs/tuple_structs/tuple_structs_cc_api_impl.rs index 2d2acc4..3d14c64 100644 --- a/cc_bindings_from_rs/test/structs/tuple_structs/tuple_structs_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/structs/tuple_structs/tuple_structs_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // tuple_structs_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/structs/unit_structs/BUILD b/cc_bindings_from_rs/test/structs/unit_structs/BUILD index 18321b8..e8d6940 100644 --- a/cc_bindings_from_rs/test/structs/unit_structs/BUILD +++ b/cc_bindings_from_rs/test/structs/unit_structs/BUILD
@@ -47,6 +47,6 @@ srcs = ["unit_structs_test.cc"], deps = [ ":unit_structs_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/structs/unit_structs/unit_structs_cc_api.h b/cc_bindings_from_rs/test/structs/unit_structs/unit_structs_cc_api.h index dd8cee1..70f5184 100644 --- a/cc_bindings_from_rs/test/structs/unit_structs/unit_structs_cc_api.h +++ b/cc_bindings_from_rs/test/structs/unit_structs/unit_structs_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // unit_structs_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_STRUCTS_UNIT_STRUCTS_UNIT_STRUCTS_GOLDEN
diff --git a/cc_bindings_from_rs/test/structs/unit_structs/unit_structs_cc_api_impl.rs b/cc_bindings_from_rs/test/structs/unit_structs/unit_structs_cc_api_impl.rs index dae6529..5f9d75d 100644 --- a/cc_bindings_from_rs/test/structs/unit_structs/unit_structs_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/structs/unit_structs/unit_structs_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // unit_structs_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/tuples/BUILD b/cc_bindings_from_rs/test/tuples/BUILD index 3aacfc2..36cbe4a 100644 --- a/cc_bindings_from_rs/test/tuples/BUILD +++ b/cc_bindings_from_rs/test/tuples/BUILD
@@ -41,6 +41,6 @@ srcs = ["tuples_test.cc"], deps = [ ":tuples_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/type_aliases/BUILD b/cc_bindings_from_rs/test/type_aliases/BUILD index 4955004..ea9e962 100644 --- a/cc_bindings_from_rs/test/type_aliases/BUILD +++ b/cc_bindings_from_rs/test/type_aliases/BUILD
@@ -29,6 +29,6 @@ srcs = ["type_aliases_test.cc"], deps = [ ":type_aliases_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/unions/BUILD b/cc_bindings_from_rs/test/unions/BUILD index 6dab82d..85b4bec 100644 --- a/cc_bindings_from_rs/test/unions/BUILD +++ b/cc_bindings_from_rs/test/unions/BUILD
@@ -47,6 +47,6 @@ srcs = ["unions_test.cc"], deps = [ ":unions_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/unions/unions_cc_api.h b/cc_bindings_from_rs/test/unions/unions_cc_api.h index 748ec7b..4c992cc 100644 --- a/cc_bindings_from_rs/test/unions/unions_cc_api.h +++ b/cc_bindings_from_rs/test/unions/unions_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // unions_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_UNIONS_UNIONS_GOLDEN
diff --git a/cc_bindings_from_rs/test/unions/unions_cc_api_impl.rs b/cc_bindings_from_rs/test/unions/unions_cc_api_impl.rs index 9488413..e7307c0 100644 --- a/cc_bindings_from_rs/test/unions/unions_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/unions/unions_cc_api_impl.rs
@@ -4,7 +4,7 @@ // Automatically @generated C++ bindings for the following Rust crate: // unions_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![allow(unused_unsafe, deprecated, non_snake_case, unreachable_code)] #![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/unwinding/BUILD b/cc_bindings_from_rs/test/unwinding/BUILD index 402e0b7..afa0a56 100644 --- a/cc_bindings_from_rs/test/unwinding/BUILD +++ b/cc_bindings_from_rs/test/unwinding/BUILD
@@ -27,6 +27,6 @@ srcs = ["unwinding_test.cc"], deps = [ ":panic_function_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/cc_bindings_from_rs/test/uses/BUILD b/cc_bindings_from_rs/test/uses/BUILD index 3ca4bc6..1880d0d 100644 --- a/cc_bindings_from_rs/test/uses/BUILD +++ b/cc_bindings_from_rs/test/uses/BUILD
@@ -36,6 +36,6 @@ srcs = ["uses_test.cc"], deps = [ ":uses_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/common/BUILD b/common/BUILD index 89da2d6..d1c0fbb 100644 --- a/common/BUILD +++ b/common/BUILD
@@ -24,7 +24,7 @@ name = "arc_anyhow", srcs = ["arc_anyhow.rs"], deps = [ - "@crate_index//:anyhow", + "@crate_index//:anyhow", # v1 ], ) @@ -53,9 +53,9 @@ ":annotation_reader", ":status_test_matchers", ":string_view_conversion", + "//testing/base/public:gunit_main", "@abseil-cpp//absl/log:check", "@abseil-cpp//absl/strings:string_view", - "@googletest//:gtest_main", "@llvm-project//clang:testing", ], ) @@ -74,11 +74,11 @@ deps = [ ":arc_anyhow", "//common:dyn_format", - "@crate_index//:heck", - "@crate_index//:phf", + "@crate_index//:heck", # v0_5 + "@crate_index//:phf", # v0_11 "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:syn", # v1 "@crate_index//:unicode-ident", ], ) @@ -94,7 +94,7 @@ ":token_stream_matchers", ":token_stream_printer", "@crate_index//:googletest", - "@crate_index//:itertools", + "@crate_index//:itertools", # v0_13 ], ) @@ -102,8 +102,8 @@ name = "crubit_feature", srcs = ["crubit_feature.rs"], deps = [ - "@crate_index//:flagset", - "@crate_index//:serde", + "@crate_index//:flagset", # v0_4 + "@crate_index//:serde", # v1 ], ) @@ -111,7 +111,7 @@ name = "dyn_format", srcs = ["dyn_format.rs"], deps = [ - "@crate_index//:anyhow", + "@crate_index//:anyhow", # v1 ], ) @@ -129,7 +129,7 @@ crate = ":crubit_feature", deps = [ "@crate_index//:googletest", - "@crate_index//:serde_json", + "@crate_index//:serde_json", # v1 ], ) @@ -161,7 +161,7 @@ name = "interner", srcs = ["interner.rs"], deps = [ - "@crate_index//:bumpalo", + "@crate_index//:bumpalo", # v3 ], ) @@ -170,7 +170,7 @@ srcs = ["interner_test.rs"], deps = [ ":interner", - "@crate_index//:bumpalo", + "@crate_index//:bumpalo", # v3 "@crate_index//:googletest", ], ) @@ -228,8 +228,8 @@ ], deps = [ "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:syn", # v1 ], ) @@ -279,8 +279,8 @@ deps = [ ":token_stream_matchers_fastpath", ":token_stream_printer", - "@crate_index//:anyhow", - "@crate_index//:indenter", + "@crate_index//:anyhow", # v1 + "@crate_index//:indenter", # v0_3 "@crate_index//:proc-macro2", ], ) @@ -295,7 +295,7 @@ ], deps = [ "@crate_index//:googletest", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -306,7 +306,7 @@ visibility = ["//visibility:private"], deps = [ ":token_stream_printer", - "@crate_index//:anyhow", + "@crate_index//:anyhow", # v1 "@crate_index//:proc-macro2", ], ) @@ -318,7 +318,7 @@ ], deps = [ "//common:ffi_types", - "@crate_index//:anyhow", + "@crate_index//:anyhow", # v1 "@crate_index//:proc-macro2", ], ) @@ -332,8 +332,8 @@ ], deps = [ "@crate_index//:googletest", - "@crate_index//:quote", - "@crate_index//:tempfile", + "@crate_index//:quote", # v1 + "@crate_index//:tempfile", # v3 ], ) @@ -384,7 +384,7 @@ deps = [ ":arc_anyhow", ":error_report", - "@crate_index//:anyhow", + "@crate_index//:anyhow", # v1 ], ) @@ -396,7 +396,7 @@ ":error_report", ":errors", "@crate_index//:googletest", - "@crate_index//:serde_json", + "@crate_index//:serde_json", # v1 ], ) @@ -406,10 +406,10 @@ visibility = ["//:__subpackages__"], deps = [ ":arc_anyhow", - "@crate_index//:anyhow", - "@crate_index//:regex", - "@crate_index//:serde", - "@crate_index//:serde_json", + "@crate_index//:anyhow", # v1 + "@crate_index//:regex", # v1 + "@crate_index//:serde", # v1 + "@crate_index//:serde_json", # v1 ], ) @@ -418,7 +418,7 @@ crate = ":error_report", deps = [ "@crate_index//:googletest", - "@crate_index//:serde_json", + "@crate_index//:serde_json", # v1 ], ) @@ -430,7 +430,7 @@ ], deps = [ "@crate_index//:proc-macro2", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], )
diff --git a/common/test/bidirectional_deps/BUILD b/common/test/bidirectional_deps/BUILD index 5438faa..b7b3cc1 100644 --- a/common/test/bidirectional_deps/BUILD +++ b/common/test/bidirectional_deps/BUILD
@@ -88,6 +88,6 @@ deps = [ ":leaf_cc_lib", ":middle_rs_lib_cc_api", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/common/test/bidirectional_deps/leaf_rs_lib_cc_api.h b/common/test/bidirectional_deps/leaf_rs_lib_cc_api.h index 6fd159b..ad0f721 100644 --- a/common/test/bidirectional_deps/leaf_rs_lib_cc_api.h +++ b/common/test/bidirectional_deps/leaf_rs_lib_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // leaf_rs_lib_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_COMMON_TEST_BIDIRECTIONAL_DEPS_LEAF_RS_LIB_GOLDEN
diff --git a/common/token_stream_printer.rs b/common/token_stream_printer.rs index a0ab8ac..6d4973f 100644 --- a/common/token_stream_printer.rs +++ b/common/token_stream_printer.rs
@@ -74,16 +74,20 @@ /// Like `tokens_to_string` but also runs the result through `rustfmt`. pub fn rs_tokens_to_formatted_string( tokens: TokenStream, - config: &RustfmtConfig, + config: Option<&RustfmtConfig>, ) -> Result<String> { - let tokens_string = tokens_to_string(tokens)? + let mut tokens_string = tokens_to_string(tokens)? // NOTE: This is a terrible hack. `rustfmt` became more strict about appearances of `...` // (the `DotDotDot` token) at some point in the past. This is not a precise or general // solution, but rewriting this token to a comment produces formattable code in some cases, // making test failure messages better. .replace("...", "/*...*/"); - let err = format!("Failed to rustfmt the following Rust tokens:\n\n{tokens_string}"); - rustfmt(tokens_string, config).context(err) + if let Some(config) = config { + tokens_string = rustfmt(tokens_string.clone(), config).with_context(|| { + format!("Failed to rustfmt the following Rust tokens:\n\n{tokens_string}") + })?; + } + Ok(tokens_string) } /// Like `rs_tokens_to_formatted_string`, but always using a Crubit-internal, @@ -91,15 +95,19 @@ /// should support custom `rustfmt.toml` and take the path to `rustfmt` binary /// as a cmdline argument. pub fn rs_tokens_to_formatted_string_for_tests(input: TokenStream) -> Result<String> { - rs_tokens_to_formatted_string(input, &RustfmtConfig::for_testing()) + rs_tokens_to_formatted_string(input, Some(&RustfmtConfig::for_testing())) } /// Like `tokens_to_string` but also runs the result through `clang-format`. pub fn cc_tokens_to_formatted_string( tokens: TokenStream, - clang_format_exe_path: &Path, + clang_format_exe_path: Option<&Path>, ) -> Result<String> { - clang_format(tokens_to_string(tokens)?, clang_format_exe_path) + let mut result = tokens_to_string(tokens)?; + if let Some(clang_format_exe_path) = clang_format_exe_path { + result = clang_format(result, clang_format_exe_path)?; + } + Ok(result) } /// Like `cc_tokens_to_formatted_string`, but always using a hardcoded path to @@ -470,7 +478,7 @@ fn bar() {} fn foo(x: i32, y: i32) -> i32 { x + y } }; - let output = rs_tokens_to_formatted_string(input, &cfg).unwrap(); + let output = rs_tokens_to_formatted_string(input, Some(&cfg)).unwrap(); assert_eq!( output, r#"fn bar() {} @@ -498,7 +506,7 @@ fn foo(x: i32, y: i32) -> i32 { x + y } }; - let output = rs_tokens_to_formatted_string(input, &cfg).unwrap(); + let output = rs_tokens_to_formatted_string(input, Some(&cfg)).unwrap(); assert_eq!( output, r#"fn bar() {}
diff --git a/docs/index.md b/docs/index.md index 4e60665..9ec01f4 100644 --- a/docs/index.md +++ b/docs/index.md
@@ -1,3 +1,4 @@ <!-- text located in README.md for GitHub and basic source viewing. --> -<!--#include file="/README.md"--> +{{#include ../README.md}} +
diff --git a/examples/cpp/enum/example_generated.rs b/examples/cpp/enum/example_generated.rs index bc0c5f4..994fbfa 100644 --- a/examples/cpp/enum/example_generated.rs +++ b/examples/cpp/enum/example_generated.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //examples/cpp/enum:example_lib -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, register_tool)]
diff --git a/examples/cpp/function/example_generated.rs b/examples/cpp/function/example_generated.rs index 0fa2220..7bd1e4a 100644 --- a/examples/cpp/function/example_generated.rs +++ b/examples/cpp/function/example_generated.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //examples/cpp/function:example_lib -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes)]
diff --git a/examples/cpp/method/example_generated.rs b/examples/cpp/method/example_generated.rs index a4a8af1..108c723 100644 --- a/examples/cpp/method/example_generated.rs +++ b/examples/cpp/method/example_generated.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //examples/cpp/method:example_lib -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, negative_impls)] @@ -32,18 +32,19 @@ // Generated from: examples/cpp/method/example.h;l=12 // Error while generating bindings for constructor 'Bar::Bar': + // Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::foo::Bar // Expected first reference parameter `__this` to have a lifetime, found *mut crate::foo::Bar // Generated from: examples/cpp/method/example.h;l=12 // Error while generating bindings for constructor 'Bar::Bar': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::foo::Bar // Expected first reference parameter `__this` to have a lifetime, found *mut crate::foo::Bar // Generated from: examples/cpp/method/example.h;l=12 // Error while generating bindings for constructor 'Bar::Bar': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::foo::Bar // Expected first reference parameter `__this` to have a lifetime, found *mut crate::foo::Bar
diff --git a/examples/cpp/trivial_abi_struct/example_generated.rs b/examples/cpp/trivial_abi_struct/example_generated.rs index 30daef3..0e00d90 100644 --- a/examples/cpp/trivial_abi_struct/example_generated.rs +++ b/examples/cpp/trivial_abi_struct/example_generated.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //examples/cpp/trivial_abi_struct:example_lib -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, negative_impls)] @@ -35,12 +35,13 @@ // Generated from: examples/cpp/trivial_abi_struct/example.h;l=12 // Error while generating bindings for constructor 'Position::Position': +// Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::Position // Expected first reference parameter `__this` to have a lifetime, found *mut crate::Position // Generated from: examples/cpp/trivial_abi_struct/example.h;l=12 // Error while generating bindings for constructor 'Position::Position': -// Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::Position // Expected first reference parameter `__this` to have a lifetime, found *mut crate::Position
diff --git a/examples/cpp/trivial_struct/example_generated.rs b/examples/cpp/trivial_struct/example_generated.rs index 6561f68..42e34d2 100644 --- a/examples/cpp/trivial_struct/example_generated.rs +++ b/examples/cpp/trivial_struct/example_generated.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //examples/cpp/trivial_struct:example_lib -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, negative_impls)] @@ -32,18 +32,19 @@ // Generated from: examples/cpp/trivial_struct/example.h;l=8 // Error while generating bindings for constructor 'Position::Position': +// Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::Position // Expected first reference parameter `__this` to have a lifetime, found *mut crate::Position // Generated from: examples/cpp/trivial_struct/example.h;l=8 // Error while generating bindings for constructor 'Position::Position': -// Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::Position // Expected first reference parameter `__this` to have a lifetime, found *mut crate::Position // Generated from: examples/cpp/trivial_struct/example.h;l=8 // Error while generating bindings for constructor 'Position::Position': -// Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::Position // Expected first reference parameter `__this` to have a lifetime, found *mut crate::Position
diff --git a/examples/cpp/unsafe_attributes/example_generated.rs b/examples/cpp/unsafe_attributes/example_generated.rs index 22f288c..d24f909 100644 --- a/examples/cpp/unsafe_attributes/example_generated.rs +++ b/examples/cpp/unsafe_attributes/example_generated.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //examples/cpp/unsafe_attributes:example_lib -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes)]
diff --git a/examples/rust/cpp_enum/BUILD b/examples/rust/cpp_enum/BUILD index 297b9c7..b227fe4 100644 --- a/examples/rust/cpp_enum/BUILD +++ b/examples/rust/cpp_enum/BUILD
@@ -23,7 +23,7 @@ "//support:crubit_annotate", ], deps = [ - "@crate_index//:open_enum", + "@crate_index//:open_enum", # v0_5 ], )
diff --git a/examples/rust/cpp_enum/example_generated.h b/examples/rust/cpp_enum/example_generated.h index d13434a..5ae878b 100644 --- a/examples/rust/cpp_enum/example_generated.h +++ b/examples/rust/cpp_enum/example_generated.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // example_crate_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_EXAMPLES_RUST_CPP_ENUM_EXAMPLE_CRATE_GOLDEN
diff --git a/examples/rust/enum/example_generated.h b/examples/rust/enum/example_generated.h index 948316f..488c006 100644 --- a/examples/rust/enum/example_generated.h +++ b/examples/rust/enum/example_generated.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // example_crate_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_EXAMPLES_RUST_ENUM_EXAMPLE_CRATE_GOLDEN
diff --git a/examples/rust/function/example_generated.h b/examples/rust/function/example_generated.h index 74111ef..cfc87ad 100644 --- a/examples/rust/function/example_generated.h +++ b/examples/rust/function/example_generated.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // example_crate_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_EXAMPLES_RUST_FUNCTION_EXAMPLE_CRATE_GOLDEN
diff --git a/examples/rust/library_config/example_generated.h b/examples/rust/library_config/example_generated.h index 81e3c8c..5536c4d 100644 --- a/examples/rust/library_config/example_generated.h +++ b/examples/rust/library_config/example_generated.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // example_crate_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_EXAMPLES_RUST_LIBRARY_CONFIG_EXAMPLE_CRATE_GOLDEN
diff --git a/examples/rust/non_trivial_struct/example_generated.h b/examples/rust/non_trivial_struct/example_generated.h index c758610..a880b34 100644 --- a/examples/rust/non_trivial_struct/example_generated.h +++ b/examples/rust/non_trivial_struct/example_generated.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // example_crate_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_EXAMPLES_RUST_NON_TRIVIAL_STRUCT_EXAMPLE_CRATE_GOLDEN
diff --git a/examples/rust/rust_union/example_generated.h b/examples/rust/rust_union/example_generated.h index 2674217..e1841b3 100644 --- a/examples/rust/rust_union/example_generated.h +++ b/examples/rust/rust_union/example_generated.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // example_crate_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_EXAMPLES_RUST_RUST_UNION_EXAMPLE_CRATE_GOLDEN
diff --git a/examples/rust/struct/example_generated.h b/examples/rust/struct/example_generated.h index a563b0b..db3d9b4 100644 --- a/examples/rust/struct/example_generated.h +++ b/examples/rust/struct/example_generated.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // example_crate_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_EXAMPLES_RUST_STRUCT_EXAMPLE_CRATE_GOLDEN
diff --git a/examples/rust/type_alias/example_generated.h b/examples/rust/type_alias/example_generated.h index 6311af5..1b5318c 100644 --- a/examples/rust/type_alias/example_generated.h +++ b/examples/rust/type_alias/example_generated.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // example_crate_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_EXAMPLES_RUST_TYPE_ALIAS_EXAMPLE_CRATE_GOLDEN
diff --git a/examples/rust/union/example_generated.h b/examples/rust/union/example_generated.h index d62d586..ee2f182 100644 --- a/examples/rust/union/example_generated.h +++ b/examples/rust/union/example_generated.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // example_crate_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_EXAMPLES_RUST_UNION_EXAMPLE_CRATE_GOLDEN
diff --git a/examples/rust/use_declaration/example_generated.h b/examples/rust/use_declaration/example_generated.h index 328e9ec..54d47ab 100644 --- a/examples/rust/use_declaration/example_generated.h +++ b/examples/rust/use_declaration/example_generated.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // example_crate_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_EXAMPLES_RUST_USE_DECLARATION_EXAMPLE_CRATE_GOLDEN
diff --git a/features/BUILD b/features/BUILD index f940da7..593b789 100644 --- a/features/BUILD +++ b/features/BUILD
@@ -23,11 +23,15 @@ # See <internal link> crubit_feature_hint( name = "supported", + compatible_with = ["//buildenv/target:non_prod"], crubit_features = SUPPORTED_FEATURES, visibility = ["//visibility:public"], ) -_WRAPPER_FEATURES = ["wrapper"] +_WRAPPER_FEATURES = [ + "wrapper", + "non_unpin_ctor", +] # A feature set containing wrapper-library Crubit features, in addition to the officially supported # features. @@ -35,6 +39,7 @@ # See <internal link> crubit_feature_hint( name = "wrapper", + compatible_with = ["//buildenv/target:non_prod"], crubit_features = SUPPORTED_FEATURES + _WRAPPER_FEATURES, visibility = _EXPERIMENTAL_CLIENTS, ) @@ -44,6 +49,7 @@ # See <internal link> crubit_feature_hint( name = "infer_operator_lifetimes", + compatible_with = ["//buildenv/target:non_prod"], crubit_features = SUPPORTED_FEATURES + ["infer_operator_lifetimes"], visibility = ["//visibility:public"], ) @@ -53,6 +59,7 @@ # See <internal link> crubit_feature_hint( name = "std_vector", + compatible_with = ["//buildenv/target:non_prod"], crubit_features = SUPPORTED_FEATURES, visibility = ["//visibility:public"], ) @@ -62,16 +69,28 @@ # See <internal link> crubit_feature_hint( name = "std_unique_ptr", + compatible_with = ["//buildenv/target:non_prod"], crubit_features = SUPPORTED_FEATURES + ["std_unique_ptr"], visibility = ["//visibility:public"], ) +# A feature set which specifically enables non-`Unpin` type handling with the `ctor` crate. +# +# See <internal link> +crubit_feature_hint( + name = "non_unpin_ctor", + compatible_with = ["//buildenv/target:non_prod"], + crubit_features = SUPPORTED_FEATURES + ["non_unpin_ctor"], + visibility = ["//visibility:public"], +) + # A feature set containing experimental Crubit features, in addition to the officially supported # features. # # See <internal link> crubit_feature_hint( name = "experimental", + compatible_with = ["//buildenv/target:non_prod"], # TODO(b/409128537): Add _WRAPPER_FEATURES on next binary release. crubit_features = ["all"], visibility = _EXPERIMENTAL_CLIENTS,
diff --git a/features/global_features.bzl b/features/global_features.bzl index c56c638..77aee12 100644 --- a/features/global_features.bzl +++ b/features/global_features.bzl
@@ -10,4 +10,5 @@ "supported", "std_vector", "std_unique_ptr", + "do_not_hardcode_status_bridge", ]
diff --git a/features/internal/BUILD b/features/internal/BUILD index 3926a26..da6c984 100644 --- a/features/internal/BUILD +++ b/features/internal/BUILD
@@ -11,6 +11,7 @@ # A feature set with a stable expansion, only for use in Bazel unit tests. crubit_feature_hint( name = "testonly_supported", + compatible_with = ["//buildenv/target:non_prod"], crubit_features = ["supported"], visibility = ["//:__subpackages__"], ) @@ -18,6 +19,7 @@ # A feature set with a stable expansion, only for use in Bazel unit tests. crubit_feature_hint( name = "testonly_experimental", + compatible_with = ["//buildenv/target:non_prod"], crubit_features = ["experimental"], visibility = ["//:__subpackages__"], )
diff --git a/lifetime_analysis/BUILD b/lifetime_analysis/BUILD index 291b4b1..c0dc9b2 100644 --- a/lifetime_analysis/BUILD +++ b/lifetime_analysis/BUILD
@@ -149,7 +149,7 @@ "//lifetime_annotations", "//lifetime_annotations:lifetime", "//lifetime_annotations/test:run_on_code", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", "@llvm-project//clang:ast", ], ) @@ -180,7 +180,7 @@ "//lifetime_annotations", "//lifetime_annotations:lifetime", "//lifetime_annotations/test:run_on_code", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", "@llvm-project//clang:ast", "@llvm-project//clang:ast_matchers", ], @@ -223,7 +223,7 @@ ":pointer_compatibility", "//lifetime_annotations", "//lifetime_annotations/test:run_on_code", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", "@llvm-project//clang:ast", "@llvm-project//clang:ast_matchers", "@llvm-project//llvm:Support",
diff --git a/lifetime_analysis/test/BUILD b/lifetime_analysis/test/BUILD index 967c703..35056db 100644 --- a/lifetime_analysis/test/BUILD +++ b/lifetime_analysis/test/BUILD
@@ -31,7 +31,7 @@ srcs = ["builtin.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -40,7 +40,7 @@ srcs = ["lifetime_params.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -49,7 +49,7 @@ srcs = ["virtual_functions.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -58,7 +58,7 @@ srcs = ["casts.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -67,7 +67,7 @@ srcs = ["callbacks.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -76,7 +76,7 @@ srcs = ["initializers.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -85,7 +85,7 @@ srcs = ["recursion.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -94,7 +94,7 @@ srcs = ["function_templates.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -103,7 +103,7 @@ srcs = ["function_calls.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -112,7 +112,7 @@ srcs = ["execution_order.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -121,7 +121,7 @@ srcs = ["control_flow.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -130,7 +130,7 @@ srcs = ["basic.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -139,7 +139,7 @@ srcs = ["static_lifetime.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -148,7 +148,7 @@ srcs = ["arrays.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -157,7 +157,7 @@ srcs = ["records.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -166,7 +166,7 @@ srcs = ["inheritance.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -175,7 +175,7 @@ srcs = ["class_templates.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -184,7 +184,7 @@ srcs = ["initialization.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -193,7 +193,7 @@ srcs = ["expr.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -202,6 +202,6 @@ srcs = ["defaulted_functions.cc"], deps = [ ":lifetime_analysis_test", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/lifetime_annotations/BUILD b/lifetime_annotations/BUILD index 69ca864..0018b3f 100644 --- a/lifetime_annotations/BUILD +++ b/lifetime_annotations/BUILD
@@ -28,7 +28,7 @@ srcs = ["lifetime_test.cc"], deps = [ ":lifetime", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -86,11 +86,11 @@ "//common:status_test_matchers", "//lifetime_annotations/test:named_func_lifetimes", "//lifetime_annotations/test:run_on_code", + "//testing/base/public:gunit_main", "@abseil-cpp//absl/status", "@abseil-cpp//absl/status:statusor", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:str_format", - "@googletest//:gtest_main", "@llvm-project//clang:ast", "@llvm-project//clang:ast_matchers", "@llvm-project//clang:tooling", @@ -115,7 +115,7 @@ deps = [ ":lifetime", ":lifetime_substitutions", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -135,7 +135,7 @@ deps = [ ":lifetime", ":lifetime_symbol_table", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/lifetime_annotations/type_lifetimes.cc b/lifetime_annotations/type_lifetimes.cc index 93f54c9..924f689 100644 --- a/lifetime_annotations/type_lifetimes.cc +++ b/lifetime_annotations/type_lifetimes.cc
@@ -759,7 +759,7 @@ } else if (auto record_type_loc = type_loc.getAs<clang::RecordTypeLoc>()) { if (auto specialization_decl = clang::dyn_cast<clang::ClassTemplateSpecializationDecl>( - record_type_loc.getOriginalDecl())) { + record_type_loc.getDecl())) { if (specialization_decl->getTemplateArgsAsWritten()) { return GetTemplateArgs( specialization_decl->getTemplateArgsAsWritten()->arguments());
diff --git a/migrator/rs_from_cc/BUILD b/migrator/rs_from_cc/BUILD index d6f9bcc..b7402c7 100644 --- a/migrator/rs_from_cc/BUILD +++ b/migrator/rs_from_cc/BUILD
@@ -71,9 +71,9 @@ deps = [ ":rs_from_cc_lib", "//common:status_test_matchers", + "//testing/base/public:gunit_main", "@abseil-cpp//absl/status", "@abseil-cpp//absl/strings:string_view", - "@googletest//:gtest_main", "@llvm-project//clang:ast", ], )
diff --git a/nullability/BUILD b/nullability/BUILD index f8d4616..60dbbbe 100644 --- a/nullability/BUILD +++ b/nullability/BUILD
@@ -270,11 +270,11 @@ hdrs = ["proto_matchers.h"], visibility = [":__subpackages__"], deps = [ + "//third_party/protobuf", "@abseil-cpp//absl/base:nullability", "@llvm-project//llvm:Support", "@llvm-project//third-party/unittest:gmock", "@llvm-project//third-party/unittest:gtest", - "@protobuf", ], ) @@ -332,6 +332,7 @@ "@llvm-project//clang:ast", "@llvm-project//clang:ast_matchers", "@llvm-project//clang:basic", + "@llvm-project//llvm:Support", ], )
diff --git a/nullability/annotations.h b/nullability/annotations.h index 6da4f03..159a9a8 100644 --- a/nullability/annotations.h +++ b/nullability/annotations.h
@@ -16,6 +16,8 @@ inline constexpr llvm::StringLiteral AbslMacroNonnull = "absl_nonnull"; inline constexpr llvm::StringLiteral AbslMacroUnknown = "absl_nullability_unknown"; +inline constexpr llvm::StringLiteral AbslMacroConflict = + "absl_nullability_conflict"; } // namespace clang::tidy::nullability #endif // THIRD_PARTY_CRUBIT_NULLABILITY_ANNOTATIONS_H_
diff --git a/nullability/inference/BUILD b/nullability/inference/BUILD index c1057eb..e2d1e6f 100644 --- a/nullability/inference/BUILD +++ b/nullability/inference/BUILD
@@ -85,12 +85,12 @@ ":inference_cc_proto", ":merge", "//nullability:proto_matchers", + "//third_party/protobuf", "@abseil-cpp//absl/log:check", "@llvm-project//llvm:Support", "@llvm-project//third-party/unittest:gmock", "@llvm-project//third-party/unittest:gtest", "@llvm-project//third-party/unittest:gtest_main", - "@protobuf", ], ) @@ -99,6 +99,7 @@ srcs = ["inferable.cc"], hdrs = ["inferable.h"], deps = [ + ":inference_cc_proto", "//nullability:type_nullability", "@llvm-project//clang:ast", "@llvm-project//clang:basic", @@ -116,6 +117,7 @@ "@llvm-project//clang:basic", "@llvm-project//clang:testing", "@llvm-project//llvm:Support", + "@llvm-project//third-party/unittest:gmock", "@llvm-project//third-party/unittest:gtest", "@llvm-project//third-party/unittest:gtest_main", ],
diff --git a/nullability/inference/collect_evidence.cc b/nullability/inference/collect_evidence.cc index 6015dd9..23f90c2 100644 --- a/nullability/inference/collect_evidence.cc +++ b/nullability/inference/collect_evidence.cc
@@ -141,19 +141,19 @@ // Filter for Nullability relevance. Optimization note: we filter // *after* calling getOverridden on the assumption that, for irrelevant // methods, it is cheaper, on average, to call `getOverridden` than - // `countInferableSlots`. But, no data informed this choice. - int SlotCount = countInferableSlots(*MD); + // `getInferableSlotIndices`. But, no data informed this choice. + llvm::SmallVector<int> SlotIndices = getInferableSlotIndices(*MD); // No slots -> irrelevant method. - if (SlotCount == 0) return true; + if (SlotIndices.empty()) return true; std::string_view USR = getOrGenerateUSR(USRCache, *MD); if (USR.empty()) return true; for (auto &O : Overridden) { auto &S = Index.Overrides[O.getKey()]; - // SlotCount of MD must equal that of any methods it overrides, so we - // can use it set their SlotCount. - S.SlotCount = SlotCount; + // MD must have the same inferable slot indices as any methods it + // overrides, so we can set their SlotIndices from MD's. + S.SlotIndices = SlotIndices; S.OverridingUSRs.insert(USR); } Index.Bases[USR] = std::move(Overridden); @@ -511,6 +511,7 @@ std::vector<std::string_view> Targets = getAdditionalTargetsForVirtualMethod( E.symbol().usr(), E.kind(), E.slot() == SLOT_RETURN_TYPE, Index); + *E.mutable_propagated_from() = E.symbol(); for (std::string_view USR : Targets) { E.mutable_symbol()->set_usr(USR); Emit(E);
diff --git a/nullability/inference/collect_evidence.h b/nullability/inference/collect_evidence.h index 89a61ca..b3e9406 100644 --- a/nullability/inference/collect_evidence.h +++ b/nullability/inference/collect_evidence.h
@@ -7,6 +7,7 @@ #include <algorithm> #include <memory> +#include <ostream> #include <utility> #include <vector> @@ -22,10 +23,15 @@ #include "clang/Analysis/FlowSensitive/Solver.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/FunctionExtras.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLFunctionalExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" namespace clang::tidy::nullability { @@ -51,9 +57,23 @@ // Summarizes a method for the purpose of aligning evidence across // virtual-method overrides. struct MethodSummary { - int SlotCount; + llvm::SmallVector<int> SlotIndices; // USRs of all methods that (transitively) override this method. llvm::StringSet<> OverridingUSRs; + + // Enable llvm StringMap testing utilities to print MethodSummary to ease + // debugging of tests. + friend std::ostream& operator<<(std::ostream& OS, + const MethodSummary& Summary) { + OS << "{\nSlotIndices: {" + << llvm::join( + llvm::map_range(Summary.SlotIndices, + [](int Index) { return llvm::to_string(Index); }), + ", ") + << "},\n"; + return OS << "OverridingUSRs: {" + << llvm::join(Summary.OverridingUSRs.keys(), ", ") << "}\n}\n"; + } }; struct VirtualMethodIndex { @@ -86,7 +106,7 @@ SortedFingerprintVector &operator=(const SortedFingerprintVector &) = delete; explicit SortedFingerprintVector(std::vector<SlotFingerprint> &&V) : Vector(std::move(V)) { - if (!std::is_sorted(Vector.begin(), Vector.end())) { + if (!llvm::is_sorted(Vector)) { // Performance is much improved if the incoming vector is already sorted, // but this is not a requirement. llvm::errs() << "Previous inferences are not sorted. Performance may be " @@ -116,12 +136,12 @@ } } // Remove the duplicates before continuing. - Vector.erase(std::unique(Vector.begin(), Vector.end()), Vector.end()); + Vector.erase(llvm::unique(Vector), Vector.end()); } } bool contains(SlotFingerprint Fingerprint) const { - return std::binary_search(Vector.begin(), Vector.end(), Fingerprint); + return llvm::binary_search(Vector, Fingerprint); } private:
diff --git a/nullability/inference/collect_evidence_test.cc b/nullability/inference/collect_evidence_test.cc index 6fbb615..68a074c 100644 --- a/nullability/inference/collect_evidence_test.cc +++ b/nullability/inference/collect_evidence_test.cc
@@ -31,6 +31,7 @@ #include "clang/Testing/TestAST.h" #include "third_party/llvm/llvm-project/clang/unittests/Analysis/FlowSensitive/TestingSupport.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/ErrorHandling.h" @@ -38,7 +39,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Testing/ADT/StringMapEntry.h" #include "llvm/Testing/Support/Error.h" -#include "external/llvm-project/third-party/unittest/googlemock/include/gmock/gmock.h" // IWYU pragma: keep +#include "external/llvm-project/third-party/unittest/googlemock/include/gmock/gmock.h" #include "external/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h" namespace clang::tidy::nullability { @@ -84,11 +85,6 @@ #define CHECK_NE(A, B) (A, B) )cc"; -MATCHER_P3(isEvidenceMatcher, SlotMatcher, KindMatcher, SymbolMatcher, "") { - return SlotMatcher.Matches(static_cast<Slot>(arg.slot())) && - KindMatcher.Matches(arg.kind()) && SymbolMatcher.Matches(arg.symbol()); -} - MATCHER_P(functionNamed, Name, "") { return llvm::StringRef(arg.usr()).contains( ("@" + llvm::Twine(Name) + "#").str()); @@ -127,25 +123,49 @@ ("@F@" + llvm::Twine(FunctionName) + "#").str()) && arg.usr().ends_with(("@" + llvm::Twine(VarName)).str()); } +} // namespace -auto localVarNamed(llvm::StringRef VarName, - llvm::StringRef FunctionName = "target") { +static auto localVarNamed(llvm::StringRef VarName, + llvm::StringRef FunctionName = "target") { return localVarNamedImpl(VarName, FunctionName); } -testing::Matcher<const Evidence&> evidence( - testing::Matcher<Slot> S, testing::Matcher<Evidence::Kind> Kind, - testing::Matcher<const Symbol&> SymbolMatcher = functionNamed("target")) { - return isEvidenceMatcher(S, Kind, SymbolMatcher); +namespace { +MATCHER_P3(isEvidenceMatcher, SlotMatcher, KindMatcher, SymbolMatcher, "") { + return SlotMatcher.Matches(static_cast<Slot>(arg.slot())) && + KindMatcher.Matches(arg.kind()) && SymbolMatcher.Matches(arg.symbol()); } +MATCHER(notPropagated, "") { return !arg.has_propagated_from(); } + +MATCHER_P(propagatedFrom, PropagatedFromMatcher, "") { + return PropagatedFromMatcher.Matches(arg.propagated_from()); +} +} // namespace + +static testing::Matcher<const Evidence&> evidence( + testing::Matcher<Slot> S, testing::Matcher<Evidence::Kind> Kind, + testing::Matcher<const Symbol&> SymbolMatcher = functionNamed("target")) { + return AllOf(isEvidenceMatcher(S, Kind, SymbolMatcher), notPropagated()); +} + +static testing::Matcher<const Evidence&> evidencePropagatedFrom( + testing::Matcher<const Symbol&> PropagatedFromMatcher, + testing::Matcher<Slot> S, testing::Matcher<Evidence::Kind> Kind, + testing::Matcher<const Symbol&> SymbolMatcher = functionNamed("target")) { + return AllOf(isEvidenceMatcher(S, Kind, SymbolMatcher), + propagatedFrom(PropagatedFromMatcher)); +} + +namespace { enum class CollectionMode { kTestWithSummaries, kTestDirectly, }; +} // namespace // Helper to get a string representation of the CollectionMode for test names. -std::string printToString(CollectionMode Mode) { +static std::string printToString(CollectionMode Mode) { switch (Mode) { case CollectionMode::kTestWithSummaries: return "WithSummaries"; @@ -155,7 +175,7 @@ llvm_unreachable("Unknown CollectionMode"); } -std::vector<Evidence> collectFromDefinitionDirectly( +static std::vector<Evidence> collectFromDefinitionDirectly( clang::TestAST& AST, const Decl& Definition, const NullabilityPragmas& Pragmas, PreviousInferences InputInferences = {}) { @@ -173,8 +193,8 @@ return Results; } -llvm::Expected<CFGSummary> summarizeDefinitionNamed(llvm::StringRef TargetName, - llvm::StringRef Source) { +static llvm::Expected<CFGSummary> summarizeDefinitionNamed( + llvm::StringRef TargetName, llvm::StringRef Source) { USRCache UsrCache; NullabilityPragmas Pragmas; clang::TestAST AST(getAugmentedTestInputs(Source, Pragmas)); @@ -186,14 +206,14 @@ /// Provides a default function-name-cased value for TargetName in /// collectEvidenceFromDefinitionNamed, which puts TargetName first for /// readability. -llvm::Expected<CFGSummary> summarizeTargetFuncDefinition( +static llvm::Expected<CFGSummary> summarizeTargetFuncDefinition( llvm::StringRef Source) { return summarizeDefinitionNamed("target", Source); } // Returns both an error and a vector to represent partial computations -- those // that fail after producing some results. -std::pair<llvm::Error, std::vector<Evidence>> +static std::pair<llvm::Error, std::vector<Evidence>> collectFromDefinitionViaSummaryWithErrors( clang::TestAST& AST, const Decl& Definition, const NullabilityPragmas& Pragmas, @@ -222,7 +242,7 @@ Results}; } -std::vector<Evidence> collectFromDefinitionViaSummary( +static std::vector<Evidence> collectFromDefinitionViaSummary( clang::TestAST& AST, const Decl& Definition, const NullabilityPragmas& Pragmas, PreviousInferences InputInferences) { auto [Err, Results] = collectFromDefinitionViaSummaryWithErrors( @@ -237,7 +257,7 @@ } // Dispatcher to collect evidence based on the CollectionMode. -std::vector<Evidence> collectFromDefinition( +static std::vector<Evidence> collectFromDefinition( clang::TestAST& AST, const Decl& Definition, const NullabilityPragmas& Pragmas, CollectionMode Mode, PreviousInferences InputInferences = {}) { @@ -252,7 +272,7 @@ llvm_unreachable("Unexpected collection mode"); } -std::vector<Evidence> collectFromDefinitionNamed( +static std::vector<Evidence> collectFromDefinitionNamed( llvm::StringRef TargetName, llvm::StringRef Source, CollectionMode Mode, PreviousInferences InputInferences = {}) { NullabilityPragmas Pragmas; @@ -264,14 +284,14 @@ /// Provides a default function-name-cased value for TargetName in /// collectFromDefinitionNamed, which puts TargetName first for readability. -std::vector<Evidence> collectFromTargetFuncDefinition( +static std::vector<Evidence> collectFromTargetFuncDefinition( llvm::StringRef Source, CollectionMode Mode, PreviousInferences InputInferences = {}) { return collectFromDefinitionNamed("target", Source, Mode, InputInferences); } template <typename MatcherT> -std::vector<Evidence> collectFromDefinitionMatching( +static std::vector<Evidence> collectFromDefinitionMatching( MatcherT Matcher, llvm::StringRef Source, CollectionMode Mode, PreviousInferences InputInferences = {}) { NullabilityPragmas Pragmas; @@ -281,8 +301,8 @@ return collectFromDefinition(AST, Definition, Pragmas, Mode, InputInferences); } -std::vector<Evidence> collectFromDecl(llvm::StringRef Source, - llvm::StringRef DeclName) { +static std::vector<Evidence> collectFromDecl(llvm::StringRef Source, + llvm::StringRef DeclName) { std::vector<Evidence> Results; NullabilityPragmas Pragmas; clang::TestAST AST(getAugmentedTestInputs(Source, Pragmas)); @@ -296,16 +316,17 @@ return Results; } -auto collectFromTargetVarDecl(llvm::StringRef Source) { +static auto collectFromTargetVarDecl(llvm::StringRef Source) { return collectFromDecl(Source, "Target"); } -auto collectFromTargetFuncDecl(llvm::StringRef Source) { +static auto collectFromTargetFuncDecl(llvm::StringRef Source) { return collectFromDecl(Source, "target"); } -MATCHER_P2(methodSummary, SlotCount, USRs, "") { - return arg.SlotCount == SlotCount && arg.OverridingUSRs == USRs; +namespace { +MATCHER_P2(methodSummary, SlotIndices, USRs, "") { + return arg.SlotIndices == SlotIndices && arg.OverridingUSRs == USRs; } TEST(GetVirtualMethodIndexTest, DerivedMultipleLayers) { @@ -313,7 +334,7 @@ static constexpr llvm::StringRef Src = R"cc( struct Base { - virtual int* foo() { return nullptr; } + virtual int* foo(char, bool, int**) { return nullptr; } // A Nullability-irrelevant method - verify omitted. virtual int irrelevant() { return 4; } @@ -323,12 +344,12 @@ }; struct Derived : public Base { - int* foo() override; + int* foo(char, bool, int**) override; int irrelevant() override { return 5; } }; struct DerivedDerived : public Derived { - int* foo() override { return nullptr; }; + int* foo(char, bool, int**) override { return nullptr; }; }; )cc"; @@ -356,8 +377,10 @@ Index.Overrides, UnorderedElementsAre( IsStringMapEntry(BaseFooUSR, - methodSummary(1, USRSet({DFooUSR, DDFooUSR}))), - IsStringMapEntry(DFooUSR, methodSummary(1, USRSet({DDFooUSR}))))); + methodSummary(llvm::SmallVector<int>{0, 3}, + USRSet({DFooUSR, DDFooUSR}))), + IsStringMapEntry(DFooUSR, methodSummary(llvm::SmallVector<int>{0, 3}, + USRSet({DDFooUSR}))))); } // TODO: b/440317964 -- Expand SummarizeDefinitionTest to cover all summarized @@ -472,7 +495,7 @@ class CollectEvidenceFromDefinitionTest : public testing::TestWithParam<CollectionMode> { protected: - CollectionMode GetMode() const { return GetParam(); } + CollectionMode getMode() const { return GetParam(); } }; INSTANTIATE_TEST_SUITE_P( @@ -500,7 +523,7 @@ // 12345678901234567890123456 // 0 1 2 - auto Evidence = collectFromTargetFuncDefinition(Code, GetMode()); + auto Evidence = collectFromTargetFuncDefinition(Code, getMode()); ASSERT_THAT(Evidence, ElementsAre(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE))); EXPECT_EQ("input.cc:1:23", Evidence.front().location()); @@ -512,7 +535,7 @@ // 123456789012345678901234567890123456789012 // 0 1 2 3 4 - auto Evidence = collectFromTargetFuncDefinition(Code, GetMode()); + auto Evidence = collectFromTargetFuncDefinition(Code, getMode()); ASSERT_THAT(Evidence, ElementsAre(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE))); EXPECT_EQ("input.cc:2:39", Evidence.front().location()); @@ -522,14 +545,14 @@ static constexpr llvm::StringRef Src = R"cc( void target() {} )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, OneParamUnused) { static constexpr llvm::StringRef Src = R"cc( void target(int *P) {} )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, OneParamUsedWithoutRestriction) { @@ -538,7 +561,7 @@ void target(int *P) { takesUnknown(P); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Not(Contains(evidence(_, _, functionNamed("target"))))); } @@ -551,7 +574,7 @@ } } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE))); } @@ -567,7 +590,7 @@ B->y(); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE), evidence(paramSlot(1), Evidence::UNCHECKED_DEREFERENCE))); @@ -586,7 +609,7 @@ P->y(); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE), evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE), @@ -599,7 +622,7 @@ *P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, DereferenceBeforeAssignment) { @@ -611,7 +634,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE))); } @@ -623,7 +646,7 @@ *P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Not(Contains(evidence(_, Evidence::UNCHECKED_DEREFERENCE)))); } @@ -639,7 +662,7 @@ *P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Not(Contains(evidence(_, Evidence::UNCHECKED_DEREFERENCE, functionNamed("target"))))); } @@ -653,7 +676,7 @@ } } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE))); } @@ -670,7 +693,7 @@ } } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE), evidence(paramSlot(1), Evidence::UNCHECKED_DEREFERENCE), @@ -690,7 +713,7 @@ int A = *P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE))); } @@ -704,7 +727,7 @@ } } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE))); } @@ -723,7 +746,7 @@ } } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE), evidence(Slot(0), Evidence::ASSIGNED_FROM_UNKNOWN, @@ -748,7 +771,7 @@ *A; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE), evidence(Slot(0), Evidence::ASSIGNED_FROM_NONNULL, @@ -768,7 +791,7 @@ } } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(1), Evidence::UNCHECKED_DEREFERENCE))); } @@ -782,7 +805,7 @@ int A = *P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, UnreachableCode) { @@ -802,7 +825,7 @@ int A = *P3; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE))); } @@ -820,7 +843,7 @@ // Pointers to members are not supported pointer types, so no evidence is // collected. If they become a supported pointer type, this test should start // failing. - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, PointerToMemberMethod) { @@ -837,7 +860,7 @@ // Pointers to members are not supported pointer types, so no evidence is // collected. If they become a supported pointer type, this test should start // failing. - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, PointerToMemberMethodArgs) { @@ -856,7 +879,7 @@ // test should start failing. // TODO(b/309625642) We should still collect evidence for the use of `Q` as an // argument for param `I`. - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, CheckMacro) { @@ -886,7 +909,7 @@ )cc"; EXPECT_THAT( collectFromTargetFuncDefinition((CheckMacroDefinitions + BaseSrc).str(), - GetMode()), + getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ABORT_IF_NULL), evidence(paramSlot(1), Evidence::ABORT_IF_NULL), evidence(paramSlot(2), Evidence::ABORT_IF_NULL), @@ -908,7 +931,7 @@ )cc"; EXPECT_THAT( collectFromTargetFuncDefinition((CheckMacroDefinitions + BaseSrc).str(), - GetMode()), + getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ABORT_IF_NULL), evidence(paramSlot(1), Evidence::ABORT_IF_NULL), evidence(paramSlot(2), Evidence::ABORT_IF_NULL))); @@ -928,7 +951,7 @@ )cc"; EXPECT_THAT(collectFromDefinitionMatching( functionDecl(hasName("Target")), - (CheckMacroDefinitions + BaseSrc).str(), GetMode()), + (CheckMacroDefinitions + BaseSrc).str(), getMode()), IsSupersetOf({(evidence(Slot(0), Evidence::ASSIGNED_FROM_NONNULL, fieldNamed("Target::Shared")), evidence(paramSlot(0), Evidence::ABORT_IF_NULL, @@ -959,7 +982,7 @@ )cc"; EXPECT_THAT( collectFromTargetFuncDefinition((CheckMacroDefinitions + BaseSrc).str(), - GetMode()), + getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ABORT_IF_NULL), evidence(paramSlot(1), Evidence::ABORT_IF_NULL), evidence(paramSlot(2), Evidence::ABORT_IF_NULL), @@ -982,7 +1005,7 @@ )cc"; EXPECT_THAT( collectFromTargetFuncDefinition((CheckMacroDefinitions + BaseSrc).str(), - GetMode()), + getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ABORT_IF_NULL), evidence(paramSlot(1), Evidence::ABORT_IF_NULL), evidence(paramSlot(3), Evidence::ABORT_IF_NULL))); @@ -993,7 +1016,7 @@ void callee(int *Q); void target(Nullable<int *> P) { callee(P); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, functionNamed("callee")))); } @@ -1003,7 +1026,7 @@ void callee(int *Q); void target(Nonnull<int *> P) { callee(P); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT, functionNamed("callee")))); } @@ -1013,7 +1036,7 @@ void callee(int *Q); void target(int *P) { callee(P); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(0), Evidence::UNKNOWN_ARGUMENT, functionNamed("callee")))); } @@ -1027,7 +1050,7 @@ } } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, functionNamed("callee")))); } @@ -1039,7 +1062,7 @@ if (P) callee(P); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT, functionNamed("callee")))); } @@ -1054,7 +1077,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, functionNamed("callee")), evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, @@ -1068,7 +1091,7 @@ void callee(int Q); void target(int P) { callee(P); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, LValueReferenceArgsPassed) { @@ -1081,7 +1104,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::NULLABLE_REFERENCE_ARGUMENT, functionNamed("constCallee")), @@ -1111,7 +1134,7 @@ universalRef(std::move(q)); // Nonnull } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( // RValue references don't have the same invariance as lvalue // references, because accesses through the reference and @@ -1132,7 +1155,7 @@ return callee(P, Q, R); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(SmartPointerCollectEvidenceFromDefinitionTest, ArgsAndParams) { @@ -1148,7 +1171,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), AllOf(IsSupersetOf( {evidence(paramSlot(1), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")), @@ -1180,14 +1203,14 @@ hasDefaultExpressionOfVariable(); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, NullableReturn) { static constexpr llvm::StringRef Src = R"cc( int* target() { return nullptr; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN))); } @@ -1201,7 +1224,7 @@ // compiles, as the lack of return in a path is only a warning. } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::NONNULL_RETURN))); } @@ -1212,7 +1235,7 @@ return P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::NONNULL_RETURN))); } @@ -1221,7 +1244,7 @@ static constexpr llvm::StringRef Src = R"cc( int* target(int* P) { return P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::UNKNOWN_RETURN))); } @@ -1236,7 +1259,7 @@ // compiles, as the lack of return in a path is only a warning. } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN))); } @@ -1249,7 +1272,7 @@ return P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN), evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN), @@ -1265,7 +1288,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_REFERENCE_RETURN), evidence(SLOT_RETURN_TYPE, Evidence::NONNULL_REFERENCE_RETURN), @@ -1282,7 +1305,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_REFERENCE_RETURN), evidence(SLOT_RETURN_TYPE, @@ -1296,7 +1319,7 @@ return A; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL))); } @@ -1308,7 +1331,7 @@ )cc"; EXPECT_THAT( collectFromTargetFuncDefinition( - Src, GetMode(), + Src, getMode(), {.Nonnull = std::make_shared<SortedFingerprintVector>( std::vector<SlotFingerprint>{ fingerprint("c:@F@target#*I#", 0)})}), @@ -1333,7 +1356,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")))); } @@ -1346,7 +1369,7 @@ }; )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, functionNamed("target")))); } @@ -1365,7 +1388,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN), evidence(SLOT_RETURN_TYPE, Evidence::NONNULL_RETURN), @@ -1385,7 +1408,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL), // evidence for the move constructor, which we don't care much about. @@ -1398,7 +1421,7 @@ void target() { *makePtr(); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, functionNamed("makePtr")))); } @@ -1413,7 +1436,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, functionNamed("makePtr")))); } @@ -1428,7 +1451,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), Not(Contains(evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, functionNamed("makePtr"))))); } @@ -1443,7 +1466,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, functionNamed("makePtr")))); } @@ -1458,7 +1481,7 @@ void target() { makePtr()->member(); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, functionNamed("makePtr")))); } @@ -1469,14 +1492,14 @@ Nonnull<int*> makeNonnullPtr(); void target() { *makeNonnullPtr(); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, FunctionPointerCall) { static constexpr llvm::StringRef Src = R"cc( void target(void (*F)()) { F(); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE))); } @@ -1502,7 +1525,7 @@ // Ideally, we would see the Nonnull from `P`'s template parameter and collect // ASSIGNED_TO_NONNULL evidence for `I`, but the sugar doesn't carry through // the BindingDecl's `auto` type. - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, ConstAccessorDereferencedAfterCheck) { @@ -1518,7 +1541,7 @@ } } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, @@ -1535,7 +1558,7 @@ } } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, @@ -1554,7 +1577,7 @@ } } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, functionNamed("accessor")))); @@ -1572,7 +1595,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, functionNamed("operator()")))); } @@ -1584,7 +1607,7 @@ }; void target() { S{} + nullptr; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, functionNamed("operator+")))); } @@ -1595,7 +1618,7 @@ bool operator+(const S&, int*); void target() { S{} + nullptr; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(1), Evidence::NULLABLE_ARGUMENT, functionNamed("operator+")))); } @@ -1606,7 +1629,7 @@ void target() { callee(nullptr, nullptr); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, functionNamed("callee")))); } @@ -1619,7 +1642,7 @@ void target() { S{}(nullptr, nullptr); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, functionNamed("operator()")))); } @@ -1632,7 +1655,7 @@ void target(int* P) { S AnS(P, nullptr); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")), evidence(paramSlot(1), Evidence::NULLABLE_ARGUMENT, @@ -1648,7 +1671,7 @@ void target(int* P) { std::make_unique<S>(P, nullptr); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")), evidence(paramSlot(1), Evidence::NULLABLE_ARGUMENT, @@ -1664,7 +1687,7 @@ Target(int *I) : TakeNonnull(I) {} }; )cc"; - EXPECT_THAT(collectFromDefinitionNamed("Target", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("Target", Src, getMode()), Contains(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("Target")))); } @@ -1680,7 +1703,7 @@ EXPECT_THAT( collectFromDefinitionMatching( - functionDecl(hasName("Target"), parameterCountIs(0)), Src, GetMode()), + functionDecl(hasName("Target"), parameterCountIs(0)), Src, getMode()), Contains(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, functionNamed("Target")))); } @@ -1693,7 +1716,7 @@ void target(int* P, int* Q) { S AnS(P, Q); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")))); } @@ -1708,7 +1731,7 @@ void target(int* P, int* Q) { std::make_unique<S>(P, Q); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")))); } @@ -1726,7 +1749,7 @@ }; void target(int* P) { S AnS(ConvertibleToIntPtr{P}); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::ASSIGNED_TO_NONNULL, functionNamed("operator int *")), @@ -1754,7 +1777,7 @@ // evidence. However, we collect the evidence from the make_unique // instantiation and will do inference from that. EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::UNKNOWN_ARGUMENT, functionNamed("ConvertibleToIntPtr")))); } @@ -1778,7 +1801,7 @@ void target(Bar b) { std::make_unique<Foo>(b); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, @@ -1790,7 +1813,7 @@ }; )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Target", Src, GetMode()), + collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("Target")))); } @@ -1803,7 +1826,7 @@ }; )cc"; EXPECT_THAT(collectFromDefinitionMatching( - cxxConstructorDecl(isDefaultConstructor()), Src, GetMode()), + cxxConstructorDecl(isDefaultConstructor()), Src, getMode()), UnorderedElementsAre(evidence( Slot(0), Evidence::NULLPTR_DEFAULT_MEMBER_INITIALIZER, fieldNamed("Target::I")))); @@ -1819,7 +1842,7 @@ )cc"; EXPECT_THAT( collectFromDefinitionMatching(cxxConstructorDecl(isDefaultConstructor()), - Src, GetMode()), + Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, fieldNamed("Target::I")))); } @@ -1835,7 +1858,7 @@ }; )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Target", Src, GetMode()), + collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("Target")))); } @@ -1856,7 +1879,7 @@ )cc"; EXPECT_THAT(collectFromDefinitionMatching( cxxConstructorDecl(isDefaultConstructor(), hasName("Target")), - Src, GetMode()), + Src, getMode()), UnorderedElementsAre(evidence( Slot(0), Evidence::NULLPTR_DEFAULT_MEMBER_INITIALIZER, fieldNamed("Target@Sa::I")))); @@ -1870,7 +1893,7 @@ }; )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Target", Src, GetMode()), + collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, fieldNamed("Target::I")))); } @@ -1888,7 +1911,7 @@ )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Target", Src, GetMode()), + collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, fieldNamed("UnionType::I")))); } @@ -1901,7 +1924,7 @@ Nonnull<int*> I; }; )cc"; - EXPECT_THAT(collectFromDefinitionNamed("Target", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::ASSIGNED_TO_NONNULL, functionNamed("getIntPtr")), @@ -1923,7 +1946,7 @@ Target T; )cc"; EXPECT_THAT(collectFromDefinitionMatching( - cxxConstructorDecl(isDefaultConstructor()), Src, GetMode()), + cxxConstructorDecl(isDefaultConstructor()), Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::ASSIGNED_TO_NONNULL, functionNamed("getIntPtr")), @@ -1944,7 +1967,7 @@ EXPECT_THAT( collectFromDefinitionMatching( cxxConstructorDecl(unless(isImplicit()), hasName("Target")), Src, - GetMode()), + getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("Target")), @@ -1965,7 +1988,7 @@ EXPECT_THAT( collectFromDefinitionMatching( cxxConstructorDecl(unless(isImplicit()), hasName("Target")), Src, - GetMode()), + getMode()), UnorderedElementsAre( evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, fieldNamed("Target::I")), @@ -1987,7 +2010,7 @@ )cc"; EXPECT_THAT(collectFromDefinitionMatching( cxxConstructorDecl(isDefaultConstructor(), hasName("Target")), - Src, GetMode()), + Src, getMode()), UnorderedElementsAre(evidence( Slot(0), Evidence::NULLPTR_DEFAULT_MEMBER_INITIALIZER, fieldNamed("Target::I")))); @@ -2007,7 +2030,7 @@ )cc"; EXPECT_THAT(collectFromDefinitionMatching( cxxConstructorDecl(isDefaultConstructor(), hasName("Target")), - Src, GetMode()), + Src, getMode()), // By the end of the constructor body, the field is still only // default-initialized, which for smart pointers means it is null. UnorderedElementsAre( @@ -2027,7 +2050,7 @@ EXPECT_THAT( collectFromDefinitionMatching( cxxConstructorDecl(unless(isImplicit()), hasName("Target")), Src, - GetMode()), + getMode()), // Evidence collected from constructor body, which assigns a Nonnull // value, but no evidence collected from *implicit* member initializer // which default constructs to null. @@ -2054,7 +2077,7 @@ EXPECT_THAT( collectFromDefinitionMatching( cxxConstructorDecl(unless(isImplicit()), hasName("Target")), Src, - GetMode()), + getMode()), // By the end of the constructor body, the field is still potentially // default-initialized, which for smart pointers means it may be null. // We also collect from the Nonnull value assignment in the body, though @@ -2084,7 +2107,7 @@ EXPECT_THAT( collectFromDefinitionMatching( cxxConstructorDecl(unless(isImplicit()), hasName("Target")), Src, - GetMode()), + getMode()), // By the end of the constructor body, the field is no longer default // initialized to null, but is assigned from an unknown. UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_UNKNOWN, @@ -2110,7 +2133,7 @@ )cc"; EXPECT_THAT(collectFromDefinitionMatching( cxxConstructorDecl(unless(isImplicit()), hasName("Target")), - Src, GetMode()), + Src, getMode()), IsEmpty()); } @@ -2130,7 +2153,7 @@ )cc"; EXPECT_THAT(collectFromDefinitionMatching( cxxConstructorDecl(unless(isImplicit()), hasName("Target")), - Src, GetMode()), + Src, getMode()), IsEmpty()); } @@ -2155,7 +2178,7 @@ EXPECT_THAT( collectFromDefinitionMatching( cxxMethodDecl(hasName("SetUp"), ofClass(hasName("Target"))), Src, - GetMode()), + getMode()), AllOf(Contains(evidence(Slot(0), Evidence::LEFT_NOT_NULLABLE_BY_LATE_INITIALIZER, fieldNamed("Target::FieldInitializedInSetUp"))), @@ -2187,7 +2210,7 @@ )cc"; EXPECT_THAT(collectFromDefinitionMatching( cxxMethodDecl(hasName("SetUp"), ofClass(hasName("Target"))), - Src, GetMode()), + Src, getMode()), Contains(evidence( Slot(0), Evidence::LEFT_NOT_NULLABLE_BY_LATE_INITIALIZER, fieldNamed("Target::FieldInitializedInSetUp")))); @@ -2200,7 +2223,7 @@ void target(int* P) { callee(P); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")))); } @@ -2212,7 +2235,7 @@ void target(int* P, int* Q) { callee(P, Q); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL_REFERENCE, functionNamed("target")), @@ -2232,7 +2255,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")))); } @@ -2244,7 +2267,7 @@ Callee(P); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")), @@ -2263,7 +2286,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")), @@ -2283,7 +2306,7 @@ void target(int* P) { MyStruct().Callee(P); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")), evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, @@ -2298,7 +2321,7 @@ void target(int* P) { (&callee)(P); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")))); } @@ -2311,7 +2334,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")))); } @@ -2323,7 +2346,7 @@ Callee(P); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL, functionNamed("target")), @@ -2338,7 +2361,7 @@ void target() { callee(makeIntPtr()); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::ASSIGNED_TO_NONNULL, functionNamed("makeIntPtr")))); @@ -2351,7 +2374,7 @@ void target(void (*Callee)(Nonnull<int*> I)) { Callee(makeIntPtr()); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::ASSIGNED_TO_NONNULL, functionNamed("makeIntPtr")), @@ -2365,7 +2388,7 @@ void target(int* P) { callee(P); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Not(Contains(evidence(_, _, functionNamed("target"))))); } @@ -2375,7 +2398,7 @@ void target(int* P) { callee(P); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_MUTABLE_NULLABLE, functionNamed("target")))); @@ -2392,7 +2415,7 @@ callee(P); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( // The object taken by reference (P) needs to be nullable, not // necessarily the source of its value (producer). @@ -2409,7 +2432,7 @@ void target() { callee(producer()); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence( SLOT_RETURN_TYPE, Evidence::ASSIGNED_TO_MUTABLE_NULLABLE, functionNamed("producer")))); @@ -2421,7 +2444,7 @@ void target(int* P) { callee(&P); } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), AllOf(UnorderedElementsAre(evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT, functionNamed("callee"))), @@ -2440,7 +2463,7 @@ A = R; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL), evidence(paramSlot(1), Evidence::ASSIGNED_TO_NONNULL), @@ -2455,7 +2478,7 @@ A = B ? R : S; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); // TODO(b/293609145) When value nullability for conditional operators is // carried through for glvalues, this should collect the following: // UnorderedElementsAre(evidence(paramSlot(1), Evidence::ASSIGNED_TO_NONNULL), @@ -2485,7 +2508,7 @@ Nonnull<std::unique_ptr<int>> nonnull = std::move(T); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL), evidence(paramSlot(2), Evidence::ASSIGNED_TO_NONNULL), @@ -2509,7 +2532,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL_REFERENCE), // `A = Q;` copies Q into P; it doesn't make a reference to Q, @@ -2528,7 +2551,7 @@ Q = R; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(1), Evidence::ASSIGNED_FROM_UNKNOWN), evidence(Slot(0), Evidence::ASSIGNED_FROM_UNKNOWN, @@ -2545,7 +2568,7 @@ A = Q; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_MUTABLE_NULLABLE) // `A = Q;` copies Q into P; it doesn't make a reference to Q, @@ -2561,7 +2584,7 @@ Nullable<std::unique_ptr<int>>& A = P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_MUTABLE_NULLABLE, functionNamed("target")))); @@ -2573,7 +2596,7 @@ Nullable<int*>& A = P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence( paramSlot(0), Evidence::ASSIGNED_TO_MUTABLE_NULLABLE))); } @@ -2590,7 +2613,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_MUTABLE_NULLABLE), evidence(paramSlot(1), Evidence::ASSIGNED_TO_MUTABLE_NULLABLE))); @@ -2602,7 +2625,7 @@ P = nullptr; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE))); } @@ -2614,7 +2637,7 @@ P = A; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE), evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, @@ -2625,7 +2648,7 @@ static constexpr llvm::StringRef Src = R"cc( void target(int* P) { P = 0; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE))); } @@ -2635,7 +2658,7 @@ Nullable<int*> getNullable(); void target(int* P) { P = getNullable(); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE, functionNamed("target")))); @@ -2648,7 +2671,7 @@ P = A; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE))); } @@ -2661,7 +2684,7 @@ void target(S AnS) { AnS.getPtrRef() = nullptr; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::ASSIGNED_FROM_NULLABLE, functionNamed("getPtrRef")))); @@ -2674,7 +2697,7 @@ *&P = nullptr; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE))); } @@ -2692,7 +2715,7 @@ P = nullptr; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, AssignedFromNonnull) { @@ -2702,7 +2725,7 @@ P = &A; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NONNULL))); } @@ -2713,7 +2736,7 @@ P = Q; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_FROM_UNKNOWN))); } @@ -2734,7 +2757,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), // From the constructor call constructing an S; no evidence from // assignments or initializations. UnorderedElementsAre(evidence(paramSlot(0), Evidence::UNKNOWN_ARGUMENT, @@ -2751,7 +2774,7 @@ // Could in theory collect evidence for both A and B as nullable, but we don't // track null state through the conditional operator, so we don't collect // evidence for either. - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, Arithmetic) { @@ -2769,7 +2792,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ARITHMETIC), evidence(paramSlot(1), Evidence::ARITHMETIC), evidence(paramSlot(2), Evidence::ARITHMETIC), @@ -2810,7 +2833,7 @@ )cc"; EXPECT_THAT( collectFromTargetFuncDefinition((CheckMacroDefinitions + BaseSrc).str(), - GetMode()), + getMode()), IsSupersetOf( {evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, fieldNamed("S::Deref")), @@ -2861,7 +2884,7 @@ )cc"; EXPECT_THAT( collectFromTargetFuncDefinition((CheckMacroDefinitions + BaseSrc).str(), - GetMode()), + getMode()), IsSupersetOf( {evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, staticFieldNamed("MyStruct::Deref")), @@ -2911,7 +2934,7 @@ )cc"; EXPECT_THAT( collectFromTargetFuncDefinition((CheckMacroDefinitions + BaseSrc).str(), - GetMode()), + getMode()), IsSupersetOf({evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, globalVarNamed("Deref")), evidence(Slot(0), Evidence::ASSIGNED_TO_NONNULL, @@ -2939,7 +2962,7 @@ int* Target = static_cast<int*>(getNullableFromNonnull(getPtr())); )cc"; - EXPECT_THAT(collectFromDefinitionNamed("Target", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::ASSIGNED_TO_NONNULL, functionNamed("getPtr")), @@ -2952,7 +2975,7 @@ int* foo(); Nonnull<int*> Target = foo(); )cc"; - EXPECT_THAT(collectFromDefinitionNamed("Target", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::ASSIGNED_TO_NONNULL, functionNamed("foo")))); @@ -2965,7 +2988,7 @@ std::unique_ptr<int> Target; )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Target", Src, GetMode()), + collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, globalVarNamed("Target")))); } @@ -2976,7 +2999,7 @@ std::unique_ptr<int> Target = nullptr; )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Target", Src, GetMode()), + collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, globalVarNamed("Target")))); } @@ -2994,7 +3017,7 @@ S Target(&GInt, AssignedToNonnull); )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Target", Src, GetMode()), + collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT, functionNamed("S")), evidence(Slot(0), Evidence::ASSIGNED_TO_NONNULL, @@ -3014,7 +3037,7 @@ std::unique_ptr<S> Target = std::make_unique<S>(&GInt, AssignedToNonnull); )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Target", Src, GetMode()), + collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NONNULL, globalVarNamed("Target")), evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT, @@ -3038,7 +3061,7 @@ std::unique_ptr<S> Target = std::make_unique<S>(&GInt, AssignedToNonnull); )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Target", Src, GetMode()), + collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NONNULL, globalVarNamed("Target")), evidence(Slot(0), Evidence::ASSIGNED_FROM_NONNULL, @@ -3054,7 +3077,7 @@ }; )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Target", Src, GetMode()), + collectFromDefinitionNamed("Target", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, staticFieldNamed("MyStruct::Target")))); } @@ -3069,7 +3092,7 @@ int* MyStruct::Target = nullptr; )cc"; EXPECT_THAT( - collectFromDefinitionMatching(varDecl(hasInit()), Src, GetMode()), + collectFromDefinitionMatching(varDecl(hasInit()), Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, staticFieldNamed("MyStruct::Target")))); } @@ -3081,7 +3104,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, localVarNamed("P")))); } @@ -3101,7 +3124,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT), evidence(paramSlot(0), Evidence::UNKNOWN_ARGUMENT), evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT))); @@ -3115,7 +3138,7 @@ *P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Not(Contains(evidence(_, _, functionNamed("target"))))); } @@ -3127,7 +3150,7 @@ *P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Not(Contains(evidence(_, _, functionNamed("target"))))); } @@ -3140,7 +3163,7 @@ *P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, functionNamed("target")))); } @@ -3155,7 +3178,7 @@ **P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Not(Contains(evidence(_, _, functionNamed("target"))))); } @@ -3168,7 +3191,7 @@ *P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, functionNamed("target")))); } @@ -3183,7 +3206,7 @@ *P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Not(Contains(evidence(_, _, functionNamed("target"))))); } @@ -3198,7 +3221,7 @@ } } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, functionNamed("target")))); } @@ -3214,7 +3237,7 @@ // dereference safe, so we do not collect evidence for P. } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Not(Contains(evidence(_, _, functionNamed("target"))))); } @@ -3225,7 +3248,7 @@ )cc"; EXPECT_THAT( - collectFromDefinitionNamed("operator()", Src, GetMode()), + collectFromDefinitionNamed("operator()", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, globalVarNamed("P")))); } @@ -3240,7 +3263,7 @@ )cc"; EXPECT_THAT( - collectFromDefinitionNamed("operator()", Src, GetMode()), + collectFromDefinitionNamed("operator()", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, localVarNamed("P", "foo")))); } @@ -3255,7 +3278,7 @@ )cc"; EXPECT_THAT( - collectFromDefinitionNamed("operator()", Src, GetMode()), + collectFromDefinitionNamed("operator()", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, localVarNamed("P", "foo")))); } @@ -3272,7 +3295,7 @@ } )cc"; - EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, functionNamed("foo")), @@ -3309,7 +3332,7 @@ } )cc"; - EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, functionNamed("foo")), @@ -3340,7 +3363,7 @@ )cc"; EXPECT_THAT( - collectFromDefinitionNamed("operator()", Src, GetMode()), + collectFromDefinitionNamed("operator()", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, fieldNamed("A::P")), evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, @@ -3358,7 +3381,7 @@ } )cc"; - EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, functionNamed("bar")), @@ -3382,7 +3405,7 @@ } }; )cc"; - EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, getMode()), UnorderedElementsAre( evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, fieldNamed("S::F")), @@ -3408,7 +3431,7 @@ } }; )cc"; - EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, getMode()), UnorderedElementsAre( evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, fieldNamed("S::F")), @@ -3436,7 +3459,7 @@ collectFromDefinitionMatching( cxxMethodDecl(hasName("operator()"), hasAncestor(lambdaExpr(hasAncestor(lambdaExpr())))), - Src, GetMode()), + Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, localVarNamed("A", "foo")), evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, @@ -3452,7 +3475,7 @@ )cc"; EXPECT_THAT( - collectFromDefinitionNamed("operator()", Src, GetMode()), + collectFromDefinitionNamed("operator()", Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::UNCHECKED_DEREFERENCE, localVarNamed("Q", "operator()")))); } @@ -3465,7 +3488,7 @@ )cc"; EXPECT_THAT( - collectFromDefinitionMatching(varDecl(hasName("Q")), Src, GetMode()), + collectFromDefinitionMatching(varDecl(hasName("Q")), Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, localVarNamed("Q", "operator()")))); } @@ -3478,7 +3501,7 @@ }; )cc"; - EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("operator()", Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, functionNamed("operator()")), @@ -3525,9 +3548,9 @@ evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, fieldNamed("MyStruct::B"))); - EXPECT_THAT(collectFromTargetFuncDefinition(BracesAggInit, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(BracesAggInit, getMode()), ExpectedEvidenceMatcher); - EXPECT_THAT(collectFromTargetFuncDefinition(ParensAggInit, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(ParensAggInit, getMode()), ExpectedEvidenceMatcher); } @@ -3553,7 +3576,7 @@ )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, fieldNamed("Base::BaseB")), evidence(paramSlot(1), Evidence::ASSIGNED_TO_NONNULL, @@ -3579,7 +3602,7 @@ void target(int* Int) { S AnS(ConvertibleToIntPtr{Int}); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(SLOT_RETURN_TYPE, Evidence::ASSIGNED_TO_NONNULL, functionNamed("operator int *")), @@ -3607,7 +3630,7 @@ // evidence. However, we collect the evidence from the make_unique // instantiation and will do inference from that. EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::UNKNOWN_ARGUMENT, functionNamed("ConvertibleToIntPtr")))); } @@ -3627,7 +3650,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, fieldNamed("MyStruct::P")), @@ -3645,7 +3668,7 @@ static constexpr llvm::StringRef Src = R"cc( void target() { int A[3] = {}; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, @@ -3656,7 +3679,7 @@ void foo(int*); void target(Nullable<std::unique_ptr<int>> P) { foo(P.get()); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), Contains(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, functionNamed("foo")))); } @@ -3671,7 +3694,7 @@ void target() { foo({get()}); } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), IsEmpty()); + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), IsEmpty()); } TEST_P(CollectEvidenceFromDefinitionTest, ArraySubscript) { @@ -3679,7 +3702,7 @@ void target(int* P) { P[0]; } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ARRAY_SUBSCRIPT))); } @@ -3691,7 +3714,7 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ARRAY_SUBSCRIPT))); } @@ -3716,11 +3739,11 @@ } )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Derived::foo", Src, GetMode()), + collectFromDefinitionNamed("Derived::foo", Src, getMode()), UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::NONNULL_RETURN, functionNamed("Derived@F@foo")))); - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, functionNamed("Derived@F@foo")))); @@ -3736,12 +3759,13 @@ int* foo() override { return nullptr; } }; )cc"; - EXPECT_THAT( - collectFromDefinitionNamed("Derived::foo", Src, GetMode()), - UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, - functionNamed("Derived@F@foo")), - evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, - functionNamed("Base@F@foo")))); + EXPECT_THAT(collectFromDefinitionNamed("Derived::foo", Src, getMode()), + UnorderedElementsAre( + evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, + functionNamed("Derived@F@foo")), + evidencePropagatedFrom( + functionNamed("Derived@F@foo"), SLOT_RETURN_TYPE, + Evidence::NULLABLE_RETURN, functionNamed("Base@F@foo")))); // We don't currently have any evidence kinds that can force a non-reference // top-level pointer return type to be nullable from its usage, so no other @@ -3765,18 +3789,22 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), - UnorderedElementsAre(evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT, - functionNamed("Derived@F@foo")), - evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT, - functionNamed("Base@F@foo")))); + collectFromTargetFuncDefinition(Src, getMode()), + UnorderedElementsAre( + evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT, + functionNamed("Derived@F@foo")), + evidencePropagatedFrom(functionNamed("Derived@F@foo"), paramSlot(0), + Evidence::NONNULL_ARGUMENT, + functionNamed("Base@F@foo")))); - EXPECT_THAT(collectFromDefinitionNamed("Derived::foo", Src, GetMode()), - UnorderedElementsAre( - evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, - functionNamed("Derived@F@foo")), - evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, - functionNamed("Base@F@foo")))); + EXPECT_THAT( + collectFromDefinitionNamed("Derived::foo", Src, getMode()), + UnorderedElementsAre( + evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, + functionNamed("Derived@F@foo")), + evidencePropagatedFrom(functionNamed("Derived@F@foo"), paramSlot(0), + Evidence::UNCHECKED_DEREFERENCE, + functionNamed("Base@F@foo")))); } // Evidence for parameter nullable-ness should flow only from base to derived, @@ -3797,11 +3825,11 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, functionNamed("Derived@F@foo")))); - EXPECT_THAT(collectFromDefinitionNamed("Derived::foo", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("Derived::foo", Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE, functionNamed("Derived@F@foo")))); @@ -3826,18 +3854,22 @@ } )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Base::foo", Src, GetMode()), - UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::NONNULL_RETURN, - functionNamed("Base@F@foo")), - evidence(SLOT_RETURN_TYPE, Evidence::NONNULL_RETURN, - functionNamed("Derived@F@foo")))); + collectFromDefinitionNamed("Base::foo", Src, getMode()), + UnorderedElementsAre( + evidence(SLOT_RETURN_TYPE, Evidence::NONNULL_RETURN, + functionNamed("Base@F@foo")), + evidencePropagatedFrom(functionNamed("Base@F@foo"), SLOT_RETURN_TYPE, + Evidence::NONNULL_RETURN, + functionNamed("Derived@F@foo")))); - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), - UnorderedElementsAre( - evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, - functionNamed("Base@F@foo")), - evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, - functionNamed("Derived@F@foo")))); + EXPECT_THAT( + collectFromTargetFuncDefinition(Src, getMode()), + UnorderedElementsAre( + evidence(SLOT_RETURN_TYPE, Evidence::UNCHECKED_DEREFERENCE, + functionNamed("Base@F@foo")), + evidencePropagatedFrom(functionNamed("Base@F@foo"), SLOT_RETURN_TYPE, + Evidence::UNCHECKED_DEREFERENCE, + functionNamed("Derived@F@foo")))); } // Evidence for return type nullable-ness should flow only from derived to base, @@ -3853,7 +3885,7 @@ }; )cc"; EXPECT_THAT( - collectFromDefinitionNamed("Base::foo", Src, GetMode()), + collectFromDefinitionNamed("Base::foo", Src, getMode()), UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, functionNamed("Base@F@foo")))); @@ -3881,11 +3913,11 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), + collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::NONNULL_ARGUMENT, functionNamed("Base@F@foo")))); - EXPECT_THAT(collectFromDefinitionNamed("Base::foo", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("Base::foo", Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, functionNamed("Base@F@foo")))); @@ -3907,18 +3939,22 @@ } )cc"; EXPECT_THAT( - collectFromTargetFuncDefinition(Src, GetMode()), - UnorderedElementsAre(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, - functionNamed("Base@F@foo")), - evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, - functionNamed("Derived@F@foo")))); + collectFromTargetFuncDefinition(Src, getMode()), + UnorderedElementsAre( + evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, + functionNamed("Base@F@foo")), + evidencePropagatedFrom(functionNamed("Base@F@foo"), paramSlot(0), + Evidence::NULLABLE_ARGUMENT, + functionNamed("Derived@F@foo")))); - EXPECT_THAT(collectFromDefinitionNamed("Base::foo", Src, GetMode()), - UnorderedElementsAre( - evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE, - functionNamed("Base@F@foo")), - evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE, - functionNamed("Derived@F@foo")))); + EXPECT_THAT( + collectFromDefinitionNamed("Base::foo", Src, getMode()), + UnorderedElementsAre( + evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE, + functionNamed("Base@F@foo")), + evidencePropagatedFrom(functionNamed("Base@F@foo"), paramSlot(0), + Evidence::ASSIGNED_FROM_NULLABLE, + functionNamed("Derived@F@foo")))); } TEST_P(CollectEvidenceFromDefinitionTest, FromVirtualDerivedMultipleLayers) { @@ -3937,13 +3973,16 @@ )cc"; EXPECT_THAT( - collectFromDefinitionNamed("DerivedDerived::foo", Src, GetMode()), - UnorderedElementsAre(evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, - functionNamed("DerivedDerived@F@foo")), - evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, - functionNamed("Derived@F@foo")), - evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, - functionNamed("Base@F@foo")))); + collectFromDefinitionNamed("DerivedDerived::foo", Src, getMode()), + UnorderedElementsAre( + evidence(SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, + functionNamed("DerivedDerived@F@foo")), + evidencePropagatedFrom(functionNamed("DerivedDerived@F@foo"), + SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, + functionNamed("Derived@F@foo")), + evidencePropagatedFrom(functionNamed("DerivedDerived@F@foo"), + SLOT_RETURN_TYPE, Evidence::NULLABLE_RETURN, + functionNamed("Base@F@foo")))); } TEST_P(CollectEvidenceFromDefinitionTest, FromVirtualBaseMultipleLayers) { @@ -3961,14 +4000,17 @@ }; )cc"; - EXPECT_THAT(collectFromDefinitionNamed("Base::foo", Src, GetMode()), - UnorderedElementsAre( - evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE, - functionNamed("DerivedDerived@F@foo")), - evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE, - functionNamed("Derived@F@foo")), - evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE, - functionNamed("Base@F@foo")))); + EXPECT_THAT( + collectFromDefinitionNamed("Base::foo", Src, getMode()), + UnorderedElementsAre( + evidencePropagatedFrom(functionNamed("Base@F@foo"), paramSlot(0), + Evidence::ASSIGNED_FROM_NULLABLE, + functionNamed("DerivedDerived@F@foo")), + evidencePropagatedFrom(functionNamed("Base@F@foo"), paramSlot(0), + Evidence::ASSIGNED_FROM_NULLABLE, + functionNamed("Derived@F@foo")), + evidence(paramSlot(0), Evidence::ASSIGNED_FROM_NULLABLE, + functionNamed("Base@F@foo")))); } TEST_P(CollectEvidenceFromDefinitionTest, FunctionTemplate) { @@ -3985,7 +4027,7 @@ } )cc"; EXPECT_THAT( - collectFromDefinitionNamed("usage", Src, GetMode()), + collectFromDefinitionNamed("usage", Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, functionNamed("tmpl<#I>")), evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, @@ -3998,21 +4040,21 @@ EXPECT_THAT( collectFromDefinitionMatching( functionDecl(hasTemplateArgument(0, refersToType(asString("int")))), - Src, GetMode()), + Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, functionNamed("tmpl<#I>")))); EXPECT_THAT( collectFromDefinitionMatching( functionDecl(hasTemplateArgument(0, refersToType(booleanType()))), - Src, GetMode()), + Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, functionNamed("tmpl<#b>")))); EXPECT_THAT( collectFromDefinitionMatching(functionDecl(hasTemplateArgument( 0, refersToType(asString("char *")))), - Src, GetMode()), + Src, getMode()), UnorderedElementsAre(evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, functionNamed("tmpl<#*C>")))); @@ -4035,7 +4077,7 @@ void usage() { tmpl<int*>(nullptr, nullptr); } )cc"; EXPECT_THAT( - collectFromDefinitionNamed("usage", Src, GetMode()), + collectFromDefinitionNamed("usage", Src, getMode()), // Evidence is emitted for the explicit specialization, not the template. UnorderedElementsAre(evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, functionNamed("tmpl<#*I>")), @@ -4044,7 +4086,7 @@ EXPECT_THAT( collectFromDefinitionMatching( functionDecl(hasTemplateArgument(0, refersToType(asString("int *")))), - Src, GetMode()), + Src, getMode()), // Evidence is emitted for the explicit specialization, not the template. UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, @@ -4065,7 +4107,7 @@ )cc"; EXPECT_THAT( collectFromDefinitionMatching(functionDecl(isTemplateInstantiation()), - Src, GetMode()), + Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, localVarNamed("A", "tmpl<#I>")), evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, @@ -4093,7 +4135,7 @@ CCharPtr.method(nullptr); } )cc"; - EXPECT_THAT(collectFromDefinitionNamed("usage", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("usage", Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, AllOf(functionNamed("method"), @@ -4111,7 +4153,7 @@ EXPECT_THAT(collectFromDefinitionMatching( functionDecl(isTemplateInstantiation(), hasParameter(0, hasType(asString("int *")))), - Src, GetMode()), + Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, AllOf(functionNamed("method"), @@ -4145,7 +4187,7 @@ CBoolPtr.method(nullptr); } )cc"; - EXPECT_THAT(collectFromDefinitionNamed("usage", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("usage", Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, AllOf(functionNamed("method"), @@ -4167,7 +4209,7 @@ EXPECT_THAT(collectFromDefinitionMatching( functionDecl(isTemplateInstantiation(), hasParameter(0, hasType(asString("int *")))), - Src, GetMode()), + Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::UNCHECKED_DEREFERENCE, AllOf(functionNamed("method"), @@ -4204,7 +4246,7 @@ CInt.Field = nullptr; } )cc"; - EXPECT_THAT(collectFromDefinitionNamed("usage", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("usage", Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, AllOf(functionNamed("method"), @@ -4239,7 +4281,7 @@ CIntBool.Field = nullptr; } )cc"; - EXPECT_THAT(collectFromDefinitionNamed("usage", Src, GetMode()), + EXPECT_THAT(collectFromDefinitionNamed("usage", Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::NULLABLE_ARGUMENT, AllOf(functionNamed("method"), @@ -4258,7 +4300,7 @@ )cc"; EXPECT_THAT( collectFromDefinitionMatching(varDecl(isTemplateInstantiation()), Src, - GetMode()), + getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, globalVarNamed("Global>#I")))); } @@ -4279,7 +4321,7 @@ )cc"; EXPECT_THAT( collectFromDefinitionMatching( - varDecl(isVarTemplateCompleteSpecializationDecl()), Src, GetMode()), + varDecl(isVarTemplateCompleteSpecializationDecl()), Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, globalVarNamed("Global>#I")))); } @@ -4297,7 +4339,7 @@ )cc"; EXPECT_THAT( collectFromDefinitionMatching( - varDecl(isVarTemplateCompleteSpecializationDecl()), Src, GetMode()), + varDecl(isVarTemplateCompleteSpecializationDecl()), Src, getMode()), UnorderedElementsAre(evidence(Slot(0), Evidence::ASSIGNED_FROM_NULLABLE, globalVarNamed("Global>#I#b")))); } @@ -4333,14 +4375,14 @@ // results contain the evidence needed to produce our expected inferences and // do not contain the evidence only found from propagating inferences from the // first round. - auto FirstRoundResults = collectFromTargetFuncDefinition(Src, GetMode()); + auto FirstRoundResults = collectFromTargetFuncDefinition(Src, getMode()); ASSERT_THAT(FirstRoundResults, IsSupersetOf(ExpectedBothRoundResults)); for (const auto& E : ExpectedSecondRoundResults) { ASSERT_THAT(FirstRoundResults, Not(Contains(E))); } EXPECT_THAT(collectFromTargetFuncDefinition( - Src, GetMode(), + Src, getMode(), {.Nullable = std::make_shared<SortedFingerprintVector>( std::vector<SlotFingerprint>{ fingerprint(TargetUsr, paramSlot(0))}), @@ -4394,7 +4436,7 @@ // Assert first round results because they don't rely on previous inference // propagation at all and in this case are test setup and preconditions. - auto FirstRoundResults = collectFromTargetFuncDefinition(Src, GetMode()); + auto FirstRoundResults = collectFromTargetFuncDefinition(Src, getMode()); ASSERT_THAT(FirstRoundResults, IsSupersetOf(ExpectedNewResultsPerRound.at(0))); for (const auto& E : ExpectedNewResultsPerRound.at(1)) { @@ -4402,7 +4444,7 @@ } auto SecondRoundResults = collectFromTargetFuncDefinition( - Src, GetMode(), + Src, getMode(), {.Nonnull = std::make_shared<SortedFingerprintVector>( std::vector<SlotFingerprint>{ fingerprint(TargetUsr, paramSlot(0))})}); @@ -4414,7 +4456,7 @@ } auto ThirdRoundResults = collectFromTargetFuncDefinition( - Src, GetMode(), + Src, getMode(), {.Nonnull = std::make_shared<SortedFingerprintVector>( std::vector<SlotFingerprint>{ fingerprint(TargetUsr, paramSlot(0)), @@ -4428,7 +4470,7 @@ } auto FourthRoundResults = collectFromTargetFuncDefinition( - Src, GetMode(), + Src, getMode(), {.Nonnull = std::make_shared<SortedFingerprintVector>( std::vector<SlotFingerprint>{ fingerprint(TargetUsr, paramSlot(0)), @@ -4458,7 +4500,7 @@ // This test confirms that we use that information when collecting from // target's definition. EXPECT_THAT(collectFromTargetFuncDefinition( - Src, GetMode(), + Src, getMode(), {.Nonnull = std::make_shared<SortedFingerprintVector>( std::vector<SlotFingerprint>{ fingerprint(TakesToBeNonnullUsr, paramSlot(0))})}), @@ -4473,7 +4515,7 @@ return P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL))); } @@ -4485,7 +4527,7 @@ int* local_top_level_pointer = P; } )cc"; - EXPECT_THAT(collectFromTargetFuncDefinition(Src, GetMode()), + EXPECT_THAT(collectFromTargetFuncDefinition(Src, getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL))); } @@ -4500,7 +4542,7 @@ } )cc"; EXPECT_THAT(collectFromTargetFuncDefinition( - (CheckMacroDefinitions + BaseSrc).str(), GetMode()), + (CheckMacroDefinitions + BaseSrc).str(), getMode()), UnorderedElementsAre( evidence(paramSlot(0), Evidence::ASSIGNED_TO_NONNULL), evidence(paramSlot(0), Evidence::ABORT_IF_NULL))); @@ -4530,7 +4572,7 @@ auto& Decl = *selectFirst<VarTemplateSpecializationDecl>( "d", match(varDecl(isTemplateInstantiation()).bind("d"), AST.context())); - switch (GetMode()) { + switch (getMode()) { case CollectionMode::kTestWithSummaries: EXPECT_THAT_EXPECTED( summarizeDefinition(Decl, UsrCache, Pragmas), @@ -4580,7 +4622,7 @@ auto& Decl = *selectFirst<VarTemplateSpecializationDecl>( "d", match(varDecl(isTemplateInstantiation()).bind("d"), AST.context())); - switch (GetMode()) { + switch (getMode()) { case CollectionMode::kTestWithSummaries: EXPECT_THAT_EXPECTED( summarizeDefinition(Decl, UsrCache, Pragmas), @@ -4619,7 +4661,7 @@ return std::make_unique<dataflow::WatchedLiteralsSolver>( /*MaxSATIterations=*/100); }; - switch (GetMode()) { + switch (getMode()) { case CollectionMode::kTestWithSummaries: { auto [Err, Results] = collectFromDefinitionViaSummaryWithErrors( AST, Decl, Pragmas, @@ -4996,6 +5038,8 @@ struct Action : public SyntaxOnlyAction { NullabilityPragmas& Pragmas; Action(NullabilityPragmas& Pragmas) : Pragmas(Pragmas) {} + + protected: std::unique_ptr<ASTConsumer> CreateASTConsumer( CompilerInstance& CI, llvm::StringRef File) override { registerPragmaHandler(CI.getPreprocessor(), Pragmas);
diff --git a/nullability/inference/eligible_ranges.cc b/nullability/inference/eligible_ranges.cc index 08e7bf1..6269749 100644 --- a/nullability/inference/eligible_ranges.cc +++ b/nullability/inference/eligible_ranges.cc
@@ -85,6 +85,7 @@ .Case(AbslMacroNullable, true) .Case(AbslMacroNonnull, true) .Case(AbslMacroUnknown, true) + .Case(AbslMacroConflict, true) .Default(false); }
diff --git a/nullability/inference/eligible_ranges_test.cc b/nullability/inference/eligible_ranges_test.cc index ff7e0c3..23028fe 100644 --- a/nullability/inference/eligible_ranges_test.cc +++ b/nullability/inference/eligible_ranges_test.cc
@@ -1455,6 +1455,18 @@ removalRanges({Input.range("")}))))); } +TEST(RemovalRangesTest, AbslMacroConflict) { + auto Input = Annotations(R"( + void target(int *$conflict^$conflict_removal[[ absl_nullability_conflict]] P); + )"); + EXPECT_THAT( + getFunctionRanges(Input.code()), + AllOf(Each(AllOf(hasPath(MainFileName), hasNoPragmaNullability())), + UnorderedElementsAre( + AllOf(eligibleRange(1, Input.point("conflict")), + removalRanges({Input.range("conflict_removal")}))))); +} + TEST(RemovalRangesTest, SimpleAlias) { auto Input = Annotations(R"( using IntPtr = int *;
diff --git a/nullability/inference/infer_tu.cc b/nullability/inference/infer_tu.cc index dfad556..7b8b4f1 100644 --- a/nullability/inference/infer_tu.cc +++ b/nullability/inference/infer_tu.cc
@@ -20,6 +20,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLFunctionalExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/Error.h" #include "llvm/Support/raw_ostream.h" @@ -28,15 +29,42 @@ class InferenceManager { public: - InferenceManager(ASTContext& Ctx, unsigned Iterations, + InferenceManager(ASTContext& Ctx, bool UseSummaries, unsigned Iterations, llvm::function_ref<bool(const Decl&)> Filter, const NullabilityPragmas& Pragmas) - : Ctx(Ctx), Iterations(Iterations), Filter(Filter), Pragmas(Pragmas) {} + : Ctx(Ctx), + UseSummaries(UseSummaries), + Iterations(Iterations), + Filter(Filter), + Pragmas(Pragmas) {} - InferenceResults inferenceRound( + InferenceResults groupAndMergeEvidence( + std::vector<Evidence> AllEvidence) const { + // Group by symbol and then slot number. + llvm::sort(AllEvidence, [&](const Evidence& L, const Evidence& R) { + if (L.symbol().usr() != R.symbol().usr()) + return L.symbol().usr() < R.symbol().usr(); + return L.slot() < R.slot(); + }); + // For each symbol, for each slot, combine evidence into an inference. + llvm::ArrayRef<Evidence> RemainingEvidence = AllEvidence; + + InferenceResults AllInference; + while (!RemainingEvidence.empty()) { + auto Batch = RemainingEvidence.take_while([&](const Evidence& E) { + return E.symbol().usr() == RemainingEvidence.front().symbol().usr() && + E.slot() == RemainingEvidence.front().slot(); + }); + RemainingEvidence = RemainingEvidence.drop_front(Batch.size()); + AllInference[Batch.front().symbol().usr()][Slot(Batch.front().slot())] = + mergeEvidence(Batch); + } + return AllInference; + } + + InferenceResults inferenceRoundWithAST( EvidenceSites Sites, USRCache USRCache, const PreviousInferences& InferencesFromLastRound) const { - InferenceResults AllInference; std::vector<Evidence> AllEvidence; // Collect all evidence. @@ -55,25 +83,78 @@ << toString(std::move(Err)) << "\n"; } } - // Group by symbol and then slot number. - llvm::sort(AllEvidence, [&](const Evidence& L, const Evidence& R) { - if (L.symbol().usr() != R.symbol().usr()) - return L.symbol().usr() < R.symbol().usr(); - return L.slot() < R.slot(); - }); - // For each symbol, for each slot, combine evidence into an inference. - llvm::ArrayRef<Evidence> RemainingEvidence = AllEvidence; - while (!RemainingEvidence.empty()) { - auto Batch = RemainingEvidence.take_while([&](const Evidence& E) { - return E.symbol().usr() == RemainingEvidence.front().symbol().usr() && - E.slot() == RemainingEvidence.front().slot(); - }); - RemainingEvidence = RemainingEvidence.drop_front(Batch.size()); - AllInference[Batch.front().symbol().usr()][Slot(Batch.front().slot())] = - mergeEvidence(Batch); + return groupAndMergeEvidence(std::move(AllEvidence)); + } + + struct FunctionSummariesAndEvidence { + TUSummary Summary; + std::vector<Evidence> DeclarationsEvidence; + llvm::StringMap<MethodSummary> BaseToOverrides; + }; + + FunctionSummariesAndEvidence summarizeFromEvidenceSites( + const EvidenceSites& Sites, USRCache& USRCache) const { + FunctionSummariesAndEvidence Result; + + VirtualMethodIndex VMI = getVirtualMethodIndex(Ctx, USRCache); + // Test the that we can properly round-trip parts of the VMI + // with saveVirtualMethodsMap and loadVirtualMethodsMap. + *Result.Summary.mutable_overrides_to_bases() = + saveVirtualMethodsMap(VMI.Bases); + + Result.BaseToOverrides = VMI.Overrides; + + // Collect evidence for decls, and summaries for definitions. + auto DeclEmitter = evidenceEmitterWithPropagation( + [&](Evidence E) { Result.DeclarationsEvidence.push_back(E); }, + std::move(VMI)); + for (const auto* Decl : Sites.Declarations) { + if (Filter && !Filter(*Decl)) continue; + collectEvidenceFromTargetDeclaration(*Decl, DeclEmitter, USRCache, + Pragmas); } - return AllInference; + if (auto MainFile = Ctx.getSourceManager().getFileEntryRefForID( + Ctx.getSourceManager().getMainFileID())) + *Result.Summary.mutable_path() = MainFile->getName().str(); + for (const auto* Impl : Sites.Definitions) { + if (Filter && !Filter(*Impl)) continue; + + if (llvm::Expected<CFGSummary> Summary = + summarizeDefinition(*Impl, USRCache, Pragmas)) { + *Result.Summary.add_cfg_summaries() = *std::move(Summary); + } else { + llvm::errs() << "Error summarizing definition: " << Summary.takeError() + << "\n"; + } + } + return Result; + } + + InferenceResults inferenceRoundWithSummaries( + const FunctionSummariesAndEvidence& SummariesAndEvidence, + const PreviousInferences& InferencesFromLastRound) const { + std::vector<Evidence> AllEvidence = + SummariesAndEvidence.DeclarationsEvidence; + + VirtualMethodIndex VMI; + VMI.Bases = loadVirtualMethodsMap( + SummariesAndEvidence.Summary.overrides_to_bases()); + VMI.Overrides = SummariesAndEvidence.BaseToOverrides; + + // Collect evidence from summaries. + auto Emitter = evidenceEmitterWithPropagation( + [&](Evidence E) { AllEvidence.push_back(E); }, std::move(VMI)); + for (const auto& FuncSummary : + SummariesAndEvidence.Summary.cfg_summaries()) { + if (llvm::Error Err = collectEvidenceFromSummary( + FuncSummary, Emitter, InferencesFromLastRound)) { + llvm::errs() << "Error collecting evidence from summary " + << llvm::toString(std::move(Err)) << "\n"; + } + } + + return groupAndMergeEvidence(std::move(AllEvidence)); } InferenceResults iterativelyInfer() const { @@ -89,9 +170,13 @@ auto Sites = EvidenceSites::discover(Ctx); USRCache USRCache; - InferenceResults AllInference = inferenceRound(Sites, USRCache, {}); + InferenceResults AllInference; + FunctionSummariesAndEvidence SummariesAndEvidence; + if (UseSummaries) { + SummariesAndEvidence = summarizeFromEvidenceSites(Sites, USRCache); + } - for (unsigned Iteration = 1; Iteration < Iterations; ++Iteration) { + for (unsigned Iteration = 0; Iteration < Iterations; ++Iteration) { std::vector<SlotFingerprint> NullableFromLastRound; std::vector<SlotFingerprint> NonnullFromLastRound; @@ -111,18 +196,28 @@ } } - AllInference = - inferenceRound(Sites, USRCache, - {.Nullable = std::make_shared<SortedFingerprintVector>( - std::move(NullableFromLastRound)), - .Nonnull = std::make_shared<SortedFingerprintVector>( - std::move(NonnullFromLastRound))}); + if (UseSummaries) { + AllInference = inferenceRoundWithSummaries( + SummariesAndEvidence, + {.Nullable = std::make_shared<SortedFingerprintVector>( + std::move(NullableFromLastRound)), + .Nonnull = std::make_shared<SortedFingerprintVector>( + std::move(NonnullFromLastRound))}); + } else { + AllInference = inferenceRoundWithAST( + Sites, USRCache, + {.Nullable = std::make_shared<SortedFingerprintVector>( + std::move(NullableFromLastRound)), + .Nonnull = std::make_shared<SortedFingerprintVector>( + std::move(NonnullFromLastRound))}); + } } return AllInference; } private: ASTContext& Ctx; + bool UseSummaries; unsigned Iterations; llvm::function_ref<bool(const Decl&)> Filter; const NullabilityPragmas& Pragmas; @@ -130,9 +225,10 @@ } // namespace InferenceResults inferTU(ASTContext& Ctx, const NullabilityPragmas& Pragmas, - unsigned Iterations, + bool UseSummaries, unsigned Iterations, llvm::function_ref<bool(const Decl&)> Filter) { - return InferenceManager(Ctx, Iterations, Filter, Pragmas).iterativelyInfer(); + return InferenceManager(Ctx, UseSummaries, Iterations, Filter, Pragmas) + .iterativelyInfer(); } } // namespace clang::tidy::nullability
diff --git a/nullability/inference/infer_tu.h b/nullability/inference/infer_tu.h index e62116a..c786ae1 100644 --- a/nullability/inference/infer_tu.h +++ b/nullability/inference/infer_tu.h
@@ -26,10 +26,13 @@ // useful in observing the behavior of the inference system. // It also lets us write tests for the whole inference system. // +// If UseSummaries is true, generates the AST only once to produce a Summary +// and then uses that Summary for iteration. // If Filter is provided, only considers decls that return true. InferenceResults inferTU( - ASTContext &, const NullabilityPragmas &, unsigned Iterations = 1, - llvm::function_ref<bool(const Decl &)> Filter = nullptr); + ASTContext&, const NullabilityPragmas&, bool UseSummaries, + unsigned Iterations = 1, + llvm::function_ref<bool(const Decl&)> Filter = nullptr); } // namespace clang::tidy::nullability
diff --git a/nullability/inference/infer_tu_main.cc b/nullability/inference/infer_tu_main.cc index 539c984..646e293 100644 --- a/nullability/inference/infer_tu_main.cc +++ b/nullability/inference/infer_tu_main.cc
@@ -75,6 +75,13 @@ llvm::cl::desc("Include trivial inferences (annotated, no conflicts)"), llvm::cl::init(false), }; +// TODO: b/417692223 remove this flag once summaries are the default. +llvm::cl::opt<bool> UseSummaries{ + "use-summaries", + llvm::cl::desc("Generate the AST only once to produce a Summary and then " + "use that Summary for iteration"), + llvm::cl::init(false), +}; llvm::cl::opt<std::string> FileFilter{ "file-filter", llvm::cl::desc("Regular expression filenames must match to be analyzed. " @@ -232,7 +239,7 @@ llvm::errs() << "Running inference...\n"; InferenceResults Results = - inferTU(Ctx, Pragmas, Iterations, DeclFilter()); + inferTU(Ctx, Pragmas, UseSummaries, Iterations, DeclFilter()); if (PrintProtos) { for (const auto &[USR, InferencesBySlot] : Results) { llvm::outs() << "USR: " << absl::StrCat(USR) << "\n";
diff --git a/nullability/inference/infer_tu_test.cc b/nullability/inference/infer_tu_test.cc index ee5aafe..63b9b8d 100644 --- a/nullability/inference/infer_tu_test.cc +++ b/nullability/inference/infer_tu_test.cc
@@ -22,6 +22,7 @@ #include "clang/Testing/TestAST.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" #include "external/llvm-project/third-party/unittest/googlemock/include/gmock/gmock.h" #include "external/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h" @@ -62,7 +63,28 @@ AST_MATCHER(Decl, isCanonical) { return Node.isCanonicalDecl(); } -class InferTUTest : public ::testing::Test { +// TODO: b/417692223 remove the parameterization once summaries are the default. +enum class InferenceMode { + kTestWithSummaries, + kTestDirectly, +}; + +} // namespace + +// Helper to get a string representation of the InferenceMode for test names. +static std::string printToString(InferenceMode Mode) { + switch (Mode) { + case InferenceMode::kTestWithSummaries: + return "WithSummaries"; + case InferenceMode::kTestDirectly: + return "Directly"; + } + llvm_unreachable("Unknown InferenceMode"); +} + +namespace { + +class InferTUTest : public testing::TestWithParam<InferenceMode> { protected: std::optional<TestAST> AST; NullabilityPragmas Pragmas; @@ -71,7 +93,10 @@ AST.emplace(getAugmentedTestInputs(Code, Pragmas)); } - auto infer() { return inferTU(AST->context(), Pragmas); } + auto infer() { + return inferTU(AST->context(), Pragmas, + GetParam() == InferenceMode::kTestWithSummaries); + } // Returns a matcher for an InferenceResults entry. // The DeclMatcher should uniquely identify the symbol being described. @@ -95,7 +120,14 @@ } }; -TEST_F(InferTUTest, UncheckedDeref) { +INSTANTIATE_TEST_SUITE_P(InferTUTests, InferTUTest, + testing::Values(InferenceMode::kTestWithSummaries, + InferenceMode::kTestDirectly), + [](const testing::TestParamInfo<InferenceMode>& Info) { + return printToString(Info.param); + }); + +TEST_P(InferTUTest, UncheckedDeref) { build(R"cc( void target(int *P, bool Cond) { if (Cond) *P; @@ -111,7 +143,7 @@ {inferredSlot(1, Nullability::NONNULL)}))); } -TEST_F(InferTUTest, Samples) { +TEST_P(InferTUTest, Samples) { llvm::StringRef Code = "void target(int * P) { *P + *P; }\n" "void another(int X) { target(&X); }"; @@ -133,7 +165,7 @@ kind: UNCHECKED_DEREFERENCE)pb"))); } -TEST_F(InferTUTest, Annotations) { +TEST_P(InferTUTest, Annotations) { build(R"cc( int *_Nonnull target(int *A, int *B); int *_Nonnull target(int *A, int *_Nullable P) { *P; } @@ -147,7 +179,7 @@ }))); } -TEST_F(InferTUTest, AnnotationsConflict) { +TEST_P(InferTUTest, AnnotationsConflict) { build(R"cc( int *_Nonnull target(); int *_Nullable target(); @@ -158,7 +190,7 @@ {inferredSlot(0, Nullability::UNKNOWN)}))); } -TEST_F(InferTUTest, ParamsFromCallSite) { +TEST_P(InferTUTest, ParamsFromCallSite) { build(R"cc( void callee(int *P, int *Q, int *R); void target(int *A, int *_Nonnull B, int *_Nullable C) { callee(A, B, C); } @@ -173,7 +205,7 @@ }))); } -TEST_F(InferTUTest, ReturnTypeNullable) { +TEST_P(InferTUTest, ReturnTypeNullable) { build(R"cc( int* target() { return nullptr; } )cc"); @@ -182,7 +214,7 @@ {inferredSlot(0, Nullability::NULLABLE)}))); } -TEST_F(InferTUTest, ReturnTypeNonnull) { +TEST_P(InferTUTest, ReturnTypeNonnull) { build(R"cc( int *_Nonnull providesNonnull(); int *target() { return providesNonnull(); } @@ -192,7 +224,7 @@ {inferredSlot(0, Nullability::NONNULL)}))); } -TEST_F(InferTUTest, ReturnTypeNonnullAndUnknown) { +TEST_P(InferTUTest, ReturnTypeNonnullAndUnknown) { build(R"cc( int *_Nonnull providesNonnull(); int *target(bool B, int *Q) { @@ -205,7 +237,7 @@ {inferredSlot(0, Nullability::UNKNOWN)}))); } -TEST_F(InferTUTest, ReturnTypeNonnullAndNullable) { +TEST_P(InferTUTest, ReturnTypeNonnullAndNullable) { build(R"cc( int *_Nonnull providesNonnull(); int *target(bool B) { @@ -218,7 +250,7 @@ {inferredSlot(0, Nullability::NULLABLE)}))); } -TEST_F(InferTUTest, ReturnTypeDereferenced) { +TEST_P(InferTUTest, ReturnTypeDereferenced) { build(R"cc( struct S { void member(); @@ -232,7 +264,7 @@ {inferredSlot(0, Nullability::NONNULL)}))); } -TEST_F(InferTUTest, PassedToNonnull) { +TEST_P(InferTUTest, PassedToNonnull) { build(R"cc( void takesNonnull(int *_Nonnull); void target(int *P) { takesNonnull(P); } @@ -242,7 +274,7 @@ {inferredSlot(1, Nullability::NONNULL)}))); } -TEST_F(InferTUTest, PassedToMutableNullableRef) { +TEST_P(InferTUTest, PassedToMutableNullableRef) { build(R"cc( void takesMutableNullableRef(int *_Nullable &); void target(int *P) { takesMutableNullableRef(P); } @@ -252,7 +284,7 @@ {inferredSlot(1, Nullability::NULLABLE)}))); } -TEST_F(InferTUTest, AssignedFromNullable) { +TEST_P(InferTUTest, AssignedFromNullable) { build(R"cc( void target(int* P) { P = nullptr; } )cc"); @@ -261,7 +293,7 @@ {inferredSlot(1, Nullability::NULLABLE)}))); } -TEST_F(InferTUTest, CHECKMacro) { +TEST_P(InferTUTest, CHECKMacro) { build(R"cc( // macro must use the parameter, but otherwise body doesn't matter #define CHECK(X) X @@ -272,7 +304,7 @@ {inferredSlot(1, Nullability::NONNULL)}))); } -TEST_F(InferTUTest, CHECKNEMacro) { +TEST_P(InferTUTest, CHECKNEMacro) { build(R"cc( // macro must use the first parameter, but otherwise body doesn't matter #define CHECK_NE(X, Y) X @@ -295,7 +327,7 @@ inference(hasName("A"), {inferredSlot(0, Nullability::NULLABLE)})})); } -TEST_F(InferTUTest, Fields) { +TEST_P(InferTUTest, Fields) { build(R"cc( int* getIntPtr(); struct S { @@ -353,7 +385,7 @@ {inferredSlot(0, Nullability::NULLABLE)}))); } -TEST_F(InferTUTest, FieldsImplicitlyDeclaredConstructorNeverUsed) { +TEST_P(InferTUTest, FieldsImplicitlyDeclaredConstructorNeverUsed) { build(R"cc( bool *_Nullable getNullable(); struct S { @@ -373,7 +405,7 @@ Not(Contains(inference(hasName("C"), {_})))))); } -TEST_F(InferTUTest, FieldsImplicitlyDeclaredConstructorUsed) { +TEST_P(InferTUTest, FieldsImplicitlyDeclaredConstructorUsed) { build(R"cc( bool *_Nullable getNullable(); struct S { @@ -394,7 +426,7 @@ inference(hasName("C"), {inferredSlot(0, Nullability::NULLABLE)})})); } -TEST_F(InferTUTest, ConstructorCallThroughMakeUnique) { +TEST_P(InferTUTest, ConstructorCallThroughMakeUnique) { build(R"cc( #include <memory> struct S { @@ -414,7 +446,7 @@ })); } -TEST_F(InferTUTest, ConstructorCallWithConversionOperator) { +TEST_P(InferTUTest, ConstructorCallWithConversionOperator) { build(R"cc( #include <memory> struct S { @@ -437,7 +469,7 @@ })); } -TEST_F(InferTUTest, ConstructorCallThroughMakeUniqueWithConversionOperator) { +TEST_P(InferTUTest, ConstructorCallThroughMakeUniqueWithConversionOperator) { build(R"cc( #include <memory> struct S { @@ -460,7 +492,7 @@ })); } -TEST_F(InferTUTest, GlobalVariables) { +TEST_P(InferTUTest, GlobalVariables) { build(R"cc( int* getIntPtr(); @@ -482,7 +514,7 @@ {inferredSlot(0, Nullability::NONNULL)}))); } -TEST_F(InferTUTest, StaticMemberVariables) { +TEST_P(InferTUTest, StaticMemberVariables) { build(R"cc( struct S { static int* SI; @@ -501,7 +533,7 @@ inference(hasName("SB"), {inferredSlot(0, Nullability::NULLABLE)}))); } -TEST_F(InferTUTest, Locals) { +TEST_P(InferTUTest, Locals) { build(R"cc( void target() { int* A = nullptr; @@ -515,20 +547,22 @@ inference(hasName("B"), {inferredSlot(0, Nullability::NULLABLE)}))); } -TEST_F(InferTUTest, Filter) { +TEST_P(InferTUTest, Filter) { build(R"cc( int* target1() { return nullptr; } int* target2() { return nullptr; } )cc"); - EXPECT_THAT(inferTU(AST->context(), Pragmas, /*Iterations=*/1, - [&](const Decl &D) { + EXPECT_THAT(inferTU(AST->context(), Pragmas, + GetParam() == InferenceMode::kTestWithSummaries, + /*Iterations=*/1, + [&](const Decl& D) { return cast<NamedDecl>(D).getNameAsString() != "target2"; }), ElementsAre(inference(hasName("target1"), {_}))); } -TEST_F(InferTUTest, AutoNoStarType) { +TEST_P(InferTUTest, AutoNoStarType) { build(R"cc( int *_Nullable getNullable(); int *_Nonnull getNonnull(); @@ -592,7 +626,7 @@ {inferredSlot(0, Nullability::NULLABLE)}))); } -TEST_F(InferTUTest, AutoStarType) { +TEST_P(InferTUTest, AutoStarType) { build(R"cc( int *_Nullable getNullable(); @@ -657,7 +691,7 @@ {inferredSlot(0, Nullability::NULLABLE)}))); } -TEST_F(InferTUTest, IterationsPropagateInferences) { +TEST_P(InferTUTest, IterationsPropagateInferences) { build(R"cc( void takesToBeNonnull(int* X) { *X; } int* returnsToBeNonnull(int* A) { return A; } @@ -668,8 +702,10 @@ return returnsToBeNonnull(P); } )cc"); + bool UseSummaries = GetParam() == InferenceMode::kTestWithSummaries; EXPECT_THAT( - inferTU(AST->context(), Pragmas, /*Iterations=*/1), + inferTU(AST->context(), Pragmas, UseSummaries, + /*Iterations=*/1), UnorderedElementsAre( inference(hasName("target"), {inferredSlot(0, Nullability::UNKNOWN), inferredSlot(1, Nullability::NONNULL), @@ -680,7 +716,7 @@ inference(hasName("takesToBeNonnull"), {inferredSlot(1, Nullability::NONNULL)}))); EXPECT_THAT( - inferTU(AST->context(), Pragmas, /*Iterations=*/2), + inferTU(AST->context(), Pragmas, UseSummaries, /*Iterations=*/2), UnorderedElementsAre( inference(hasName("target"), {inferredSlot(0, Nullability::UNKNOWN), inferredSlot(1, Nullability::NONNULL), @@ -691,7 +727,7 @@ inference(hasName("takesToBeNonnull"), {inferredSlot(1, Nullability::NONNULL)}))); EXPECT_THAT( - inferTU(AST->context(), Pragmas, /*Iterations=*/3), + inferTU(AST->context(), Pragmas, UseSummaries, /*Iterations=*/3), UnorderedElementsAre( inference(hasName("target"), {inferredSlot(0, Nullability::UNKNOWN), inferredSlot(1, Nullability::NONNULL), @@ -703,7 +739,7 @@ inference(hasName("takesToBeNonnull"), {inferredSlot(1, Nullability::NONNULL)}))); EXPECT_THAT( - inferTU(AST->context(), Pragmas, /*Iterations=*/4), + inferTU(AST->context(), Pragmas, UseSummaries, /*Iterations=*/4), UnorderedElementsAre( inference(hasName("target"), {inferredSlot(0, Nullability::NONNULL), inferredSlot(1, Nullability::NONNULL), @@ -718,7 +754,7 @@ // This tests a case where the initial analysis before inference queries the SAT // solver (when doing a Join). -TEST_F(InferTUTest, MultipleIterationsWithJoinAndDeadCode) { +TEST_P(InferTUTest, MultipleIterationsWithJoinAndDeadCode) { build(R"cc( int* otherFunction(int* P) { *P = 0; @@ -744,7 +780,9 @@ void caller(int X) { target(&X, nullptr); } )cc"); EXPECT_THAT( - inferTU(AST->context(), Pragmas, /*Iterations=*/3), + inferTU(AST->context(), Pragmas, + GetParam() == InferenceMode::kTestWithSummaries, + /*Iterations=*/3), UnorderedElementsAre(inference(hasName("otherFunction"), {inferredSlot(0, Nullability::NONNULL), inferredSlot(1, Nullability::NONNULL)}), @@ -758,7 +796,7 @@ {inferredSlot(0, Nullability::NONNULL)}))); } -TEST_F(InferTUTest, Pragma) { +TEST_P(InferTUTest, Pragma) { build(R"cc( #pragma nullability file_default nonnull void target(int *DefaultNonnull, int *_Null_unspecified InferredNonnull, @@ -790,7 +828,7 @@ }))); } -TEST_F(InferTUTest, FunctionTemplate) { +TEST_P(InferTUTest, FunctionTemplate) { build(R"cc( template <typename T> T functionTemplate(int *P, int *_Nullable Q, T *R, T *_Nullable S, T U) { @@ -837,7 +875,7 @@ inferredSlot(4, Nullability::NULLABLE)})})); } -TEST_F(InferTUTest, LambdaWithCaptureInit) { +TEST_P(InferTUTest, LambdaWithCaptureInit) { build(R"cc( void foo() { int* P; @@ -845,7 +883,9 @@ } )cc"); EXPECT_THAT( - inferTU(AST->context(), Pragmas, /*Iterations=*/2), + inferTU(AST->context(), Pragmas, + GetParam() == InferenceMode::kTestWithSummaries, + /*Iterations=*/2), UnorderedElementsAre( inference(hasName("P"), {inferredSlot(0, Nullability::NONNULL)}), inference(hasName("Q"), {inferredSlot(0, Nullability::NONNULL)}))); @@ -853,7 +893,14 @@ using InferTUSmartPointerTest = InferTUTest; -TEST_F(InferTUSmartPointerTest, Annotations) { +INSTANTIATE_TEST_SUITE_P(InferTUSmartPointerTests, InferTUSmartPointerTest, + testing::Values(InferenceMode::kTestWithSummaries, + InferenceMode::kTestDirectly), + [](const testing::TestParamInfo<InferenceMode>& Info) { + return printToString(Info.param); + }); + +TEST_P(InferTUSmartPointerTest, Annotations) { build(R"cc( #include <memory> _Nonnull std::unique_ptr<int> target(std::unique_ptr<int> A, @@ -872,7 +919,7 @@ }))); } -TEST_F(InferTUSmartPointerTest, ParamsFromCallSite) { +TEST_P(InferTUSmartPointerTest, ParamsFromCallSite) { build(R"cc( #include <memory> #include <utility> @@ -893,7 +940,7 @@ }))); } -TEST_F(InferTUSmartPointerTest, ReturnTypeNullable) { +TEST_P(InferTUSmartPointerTest, ReturnTypeNullable) { build(R"cc( #include <memory> std::unique_ptr<int> target() { return std::unique_ptr<int>(); } @@ -903,7 +950,7 @@ {inferredSlot(0, Nullability::NULLABLE)}))); } -TEST_F(InferTUSmartPointerTest, ReturnTypeNonnull) { +TEST_P(InferTUSmartPointerTest, ReturnTypeNonnull) { build(R"cc( #include <memory> std::unique_ptr<int> target() { return std::make_unique<int>(0); } @@ -913,7 +960,7 @@ {inferredSlot(0, Nullability::NONNULL)}))); } -TEST_F(InferTUSmartPointerTest, +TEST_P(InferTUSmartPointerTest, DefaultFieldInitializersAbsentSomeLateInitializationInTestSetUp) { build(R"cc( #include <memory> @@ -979,7 +1026,14 @@ using InferTUVirtualMethodsTest = InferTUTest; -TEST_F(InferTUVirtualMethodsTest, SafeVarianceNoConflicts) { +INSTANTIATE_TEST_SUITE_P(InferTUVirtualMethodsTests, InferTUVirtualMethodsTest, + testing::Values(InferenceMode::kTestWithSummaries, + InferenceMode::kTestDirectly), + [](const testing::TestParamInfo<InferenceMode>& Info) { + return printToString(Info.param); + }); + +TEST_P(InferTUVirtualMethodsTest, SafeVarianceNoConflicts) { build(R"cc( struct Base { virtual int* foo(int* P) { @@ -1007,7 +1061,7 @@ inferredSlot(1, Nullability::NULLABLE)}))); } -TEST_F(InferTUVirtualMethodsTest, BaseConstrainsDerived) { +TEST_P(InferTUVirtualMethodsTest, BaseConstrainsDerived) { build(R"cc( struct Base { virtual int *_Nonnull foo(int *P) { @@ -1032,7 +1086,7 @@ inferredSlot(1, Nullability::NULLABLE)}))); } -TEST_F(InferTUVirtualMethodsTest, DerivedConstrainsBase) { +TEST_P(InferTUVirtualMethodsTest, DerivedConstrainsBase) { build(R"cc( struct Base { virtual int* foo(int* P); @@ -1055,7 +1109,7 @@ inferredSlot(1, Nullability::NONNULL)}))); } -TEST_F(InferTUVirtualMethodsTest, Conflict) { +TEST_P(InferTUVirtualMethodsTest, Conflict) { build(R"cc( struct Base { virtual int* foo(int* P); @@ -1089,7 +1143,7 @@ inferredSlot(1, Nullability::NONNULL, /*Conflict*/ true)}))); } -TEST_F(InferTUVirtualMethodsTest, MultipleDerived) { +TEST_P(InferTUVirtualMethodsTest, MultipleDerived) { build(R"cc( struct Base { virtual void foo(int* P) { P = nullptr; } @@ -1113,7 +1167,7 @@ {inferredSlot(1, Nullability::NULLABLE)}))); } -TEST_F(InferTUVirtualMethodsTest, MultipleBase) { +TEST_P(InferTUVirtualMethodsTest, MultipleBase) { build(R"cc( struct BaseA { virtual void foo(int* P);
diff --git a/nullability/inference/inferable.cc b/nullability/inference/inferable.cc index a2ae15c..aada32f 100644 --- a/nullability/inference/inferable.cc +++ b/nullability/inference/inferable.cc
@@ -7,6 +7,7 @@ #include <cassert> #include <optional> +#include "nullability/inference/inference.proto.h" #include "nullability/type_nullability.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" @@ -17,6 +18,7 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLFunctionalExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -198,6 +200,31 @@ return 0; } +llvm::SmallVector<int> getInferableSlotIndices(const Decl& D) { + if (const auto* Func = dyn_cast<FunctionDecl>(&D)) { + llvm::SmallVector<int> Slots; + if (hasInferable(Func->getReturnType())) Slots.push_back(SLOT_RETURN_TYPE); + // Intentionally match the iteration pattern evidence collection uses over + // function parameters when gathering inferable slots, to avoid any subtle + // differences for complex function contexts. + auto Parameters = Func->parameters(); + for (auto I = 0; I < Parameters.size(); ++I) { + const ParmVarDecl* Param = Parameters[I]; + if (hasInferable(Param->getType())) Slots.push_back(I + SLOT_PARAM); + } + return Slots; + } + if (const auto* Field = dyn_cast<FieldDecl>(&D)) { + if (hasInferable(Field->getType())) return {0}; + return {}; + } + if (const auto* Var = dyn_cast<VarDecl>(&D)) { + if (hasInferable(Var->getType())) return {0}; + return {}; + } + return {}; +} + bool isInferenceTarget(const Decl& D) { if (const auto* Func = dyn_cast<FunctionDecl>(&D)) { return
diff --git a/nullability/inference/inferable.h b/nullability/inference/inferable.h index 54a0921..2568427 100644 --- a/nullability/inference/inferable.h +++ b/nullability/inference/inferable.h
@@ -7,6 +7,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/Type.h" +#include "llvm/ADT/SmallVector.h" namespace clang::tidy::nullability { @@ -19,9 +20,16 @@ /// The number of nullability slots in this symbol's type which can be inferred. /// /// This may not be all the slots in the type: e.g. `int** X` has outer and -/// inner nullability, we may support only inferring outer. +/// inner nullability; we may support only inferring outer. int countInferableSlots(const clang::Decl &); +/// The indices of nullability slots in this symbol's type which can be +/// inferred. +/// +/// This may not be all the slots in the type: e.g. `int** X` has outer and +/// inner nullability; we may support only inferring outer. +llvm::SmallVector<int> getInferableSlotIndices(const clang::Decl&); + } // namespace clang::tidy::nullability #endif // THIRD_PARTY_CRUBIT_NULLABILITY_INFERENCE_INFERRABLE_H_
diff --git a/nullability/inference/inferable_test.cc b/nullability/inference/inferable_test.cc index 9df12e7..d1fbacf 100644 --- a/nullability/inference/inferable_test.cc +++ b/nullability/inference/inferable_test.cc
@@ -15,10 +15,10 @@ #include "clang/Basic/LLVM.h" #include "clang/Testing/TestAST.h" #include "llvm/ADT/StringRef.h" +#include "external/llvm-project/third-party/unittest/googlemock/include/gmock/gmock.h" #include "external/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h" namespace clang::tidy::nullability { -namespace { using ::clang::ast_matchers::anything; using ::clang::ast_matchers::equalsNode; using ::clang::ast_matchers::functionDecl; @@ -30,19 +30,21 @@ using ::clang::ast_matchers::namedDecl; using ::clang::ast_matchers::selectFirst; using ::clang::ast_matchers::unless; +using ::testing::IsEmpty; +using ::testing::UnorderedElementsAre; template <class T = NamedDecl> -const T &lookup(llvm::StringRef Name, ASTContext &Ctx, - const Decl *DeclContext = nullptr) { - const auto &ContextMatcher = +static const T& lookup(llvm::StringRef Name, ASTContext& Ctx, + const Decl* DeclContext = nullptr) { + const auto& ContextMatcher = DeclContext ? hasDeclContext(equalsNode(DeclContext)) : anything(); - const auto &BoundNodes = + const auto& BoundNodes = match(namedDecl(hasName(Name), ContextMatcher, unless(isImplicit())) .bind("decl"), Ctx); - const T *Match = nullptr; - for (const auto &N : BoundNodes) { - if (const auto *NAsT = N.getNodeAs<T>("decl")) { + const T* Match = nullptr; + for (const auto& N : BoundNodes) { + if (const auto* NAsT = N.getNodeAs<T>("decl")) { if (Match) ADD_FAILURE() << "Found more than one matching node for " << Name; Match = NAsT; @@ -52,6 +54,7 @@ return *Match; } +namespace { constexpr llvm::StringRef SmartPointerHeader = R"cc( namespace std { template <typename T> @@ -386,7 +389,8 @@ int*** ThreePointersOneInferable; )cc"); auto &Ctx = AST.context(); - EXPECT_EQ(1, countInferableSlots(lookup("ThreePointersOneInferable", Ctx))); + EXPECT_THAT(getInferableSlotIndices(lookup("ThreePointersOneInferable", Ctx)), + UnorderedElementsAre(0)); } TEST(InferableTest, TemplateArgumentPointersNotInferable) { @@ -630,5 +634,52 @@ } } +TEST(InferableTest, GetInferableSlotIndices) { + TestAST AST((SmartPointerHeader + R"cc( + void f1(int**, int, char, char*); + int* f2(bool, bool*); + void f3(std::unique_ptr<int>); + void f4(custom_smart_ptr<int>); + + int v1; + int* v2; + int** v3; + + class C { + int field1; + int* field2; + int** field3; + + int* method(bool, bool*); + }; + )cc") + .str()); + auto& Ctx = AST.context(); + + EXPECT_THAT(getInferableSlotIndices(lookup("f1", Ctx)), + UnorderedElementsAre(1, 4)); + EXPECT_THAT(getInferableSlotIndices(lookup("f2", Ctx)), + UnorderedElementsAre(0, 2)); + EXPECT_THAT(getInferableSlotIndices(lookup("f3", Ctx)), + UnorderedElementsAre(1)); + EXPECT_THAT(getInferableSlotIndices(lookup("f4", Ctx)), + UnorderedElementsAre(1)); + + EXPECT_THAT(getInferableSlotIndices(lookup("v1", Ctx)), IsEmpty()); + EXPECT_THAT(getInferableSlotIndices(lookup("v2", Ctx)), + UnorderedElementsAre(0)); + EXPECT_THAT(getInferableSlotIndices(lookup("v3", Ctx)), + UnorderedElementsAre(0)); + + EXPECT_THAT(getInferableSlotIndices(lookup("field1", Ctx)), IsEmpty()); + EXPECT_THAT(getInferableSlotIndices(lookup("field2", Ctx)), + UnorderedElementsAre(0)); + EXPECT_THAT(getInferableSlotIndices(lookup("field3", Ctx)), + UnorderedElementsAre(0)); + + EXPECT_THAT(getInferableSlotIndices(lookup("method", Ctx)), + UnorderedElementsAre(0, 2)); +} + } // namespace } // namespace clang::tidy::nullability
diff --git a/nullability/inference/inference.proto b/nullability/inference/inference.proto index ec93518..ee2476c 100644 --- a/nullability/inference/inference.proto +++ b/nullability/inference/inference.proto
@@ -48,6 +48,9 @@ optional Kind kind = 3; // Source location: file:line:col. Optional, for debugging only. optional string location = 4; + // If set, this evidence was originally collected from the virtual or override + // function identified by this symbol and propagated to `symbol`. + optional Symbol propagated_from = 5; // A pattern in the code that might help us determine nullability. enum Kind { @@ -183,11 +186,11 @@ message SlotPartial { map</*Kind*/ uint32, uint32> kind_count = 1; - message SampleLocations { - // A bounded number of locations are stored. - repeated string location = 1; + message SampleEvidence { + // A bounded number of evidence pieces are stored. + repeated Evidence evidence = 1; } - map</*Kind*/ uint32, SampleLocations> kind_samples = 2; + map</*Kind*/ uint32, SampleEvidence> kind_samples = 2; // Slot identifiers for which this partial is relevant. Used only for // debugging information. @@ -365,7 +368,7 @@ message LogicalContext { // optional, string-encoded formula providing an invariant across all formulas // represented in this logical context. - optional FormulaProto invariant = 1; + optional FormulaProto invariant = 1; // Int-encoded atoms and their definitions as formulas. map<uint32, FormulaProto> atom_defs = 2; @@ -400,3 +403,11 @@ // key. These must be USRs. map<string, SymbolSet> related_symbols = 1; } + +// A summary for a whole translation unit. +message TUSummary { + repeated CFGSummary cfg_summaries = 1; + optional RelatedSymbols overrides_to_bases = 2; + // Information about the TU that could be useful for debug logs. + optional string path = 3; +}
diff --git a/nullability/inference/merge.cc b/nullability/inference/merge.cc index 3f1f0fd..36203fe 100644 --- a/nullability/inference/merge.cc +++ b/nullability/inference/merge.cc
@@ -6,35 +6,42 @@ #include <array> #include <optional> -#include <utility> +#include <string> #include "absl/log/check.h" #include "nullability/inference/inference.proto.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" namespace clang::tidy::nullability { -namespace { -static void mergeSampleLocations(SlotPartial::SampleLocations &LHS, - const SlotPartial::SampleLocations &RHS) { +static void mergeSampleEvidence(SlotPartial::SampleEvidence& LHS, + const SlotPartial::SampleEvidence& RHS) { static constexpr unsigned Limit = 3; - // We don't care which we pick, but they should be unique. + // We don't care which we pick, but their locations should be unique. // Multiple instantiations of the same template are not interesting. - for (const auto &Loc : RHS.location()) { - if (LHS.location_size() >= Limit) break; - // Linear scan is fine because Limit is tiny. - if (!llvm::is_contained(LHS.location(), Loc)) LHS.add_location(Loc); + // Linear scans are fine because Limit is tiny. + llvm::SmallVector<std::string, Limit> LHSEvidenceLocations(llvm::map_range( + LHS.evidence(), [](const Evidence& E) { return E.location(); })); + for (const auto& E : RHS.evidence()) { + if (LHS.evidence_size() >= Limit) break; + if (!llvm::is_contained(LHSEvidenceLocations, E.location())) + *LHS.add_evidence() = E; } } -} // namespace - SlotPartial partialFromEvidence(const Evidence &E) { SlotPartial P; ++(*P.mutable_kind_count())[E.kind()]; - if (E.has_location()) - (*P.mutable_kind_samples())[E.kind()].add_location(E.location()); + // Save the evidence as a sample, only if it has a location. + if (E.has_location()) { + Evidence& Sample = *(*P.mutable_kind_samples())[E.kind()].add_evidence(); + Sample = E; + // Clear the symbol and slot, which are extraneous for debugging samples. + Sample.clear_symbol(); + Sample.clear_slot(); + } return P; } @@ -42,7 +49,7 @@ for (auto [Kind, Count] : RHS.kind_count()) (*LHS.mutable_kind_count())[Kind] += Count; for (const auto &[Kind, Samples] : RHS.kind_samples()) - mergeSampleLocations((*LHS.mutable_kind_samples())[Kind], Samples); + mergeSampleEvidence((*LHS.mutable_kind_samples())[Kind], Samples); } // Form a nullability conclusion from a set of evidence. @@ -50,12 +57,9 @@ SlotInference Inference; if (P.kind_count_size() == 0) return Inference; - // Reconstitute samples, if we have them. for (const auto &[Kind, Samples] : P.kind_samples()) { - for (const auto &Loc : Samples.location()) { - auto *Sample = Inference.add_sample_evidence(); - Sample->set_location(Loc); - Sample->set_kind(static_cast<Evidence::Kind>(Kind)); + for (const auto& Sample : Samples.evidence()) { + *Inference.add_sample_evidence() = Sample; } } llvm::stable_sort(*Inference.mutable_sample_evidence(), @@ -73,9 +77,8 @@ return Inference; } -namespace { -void update(std::optional<InferResult> &Result, - Nullability ImpliedNullability) { +static void update(std::optional<InferResult>& Result, + Nullability ImpliedNullability) { if (!Result) { Result = {ImpliedNullability}; return; @@ -84,7 +87,6 @@ // Leave the existing Nullability. Result->Conflict = true; } -} // namespace InferResult infer(llvm::ArrayRef<unsigned> Counts, bool EnableSoftRules) { CHECK_EQ(Counts.size(), Evidence::Kind_MAX + 1);
diff --git a/nullability/inference/merge_test.cc b/nullability/inference/merge_test.cc index 6e726d6..03cf9d7 100644 --- a/nullability/inference/merge_test.cc +++ b/nullability/inference/merge_test.cc
@@ -15,29 +15,31 @@ #include "google/protobuf/text_format.h" namespace clang::tidy::nullability { -namespace { - template <typename T> -T proto(llvm::StringRef Text) { +static T proto(llvm::StringRef Text) { T Result; CHECK(google::protobuf::TextFormat::ParseFromString(Text, &Result)); return Result; } +namespace { TEST(PartialFromEvidenceTest, ContainsEvidenceInfo) { - EXPECT_THAT(partialFromEvidence(proto<Evidence>(R"pb( - symbol { usr: "func" } - slot: 1 - kind: UNCHECKED_DEREFERENCE - location: "foo.cc:42" - )pb")), - EqualsProto(R"pb( - kind_count { key: 3 value: 1 } - kind_samples { - key: 3 - value { location: "foo.cc:42" } - } - )pb")); + EXPECT_THAT( + partialFromEvidence(proto<Evidence>(R"pb( + symbol { usr: "func" } + slot: 1 + kind: UNCHECKED_DEREFERENCE + location: "foo.cc:42" + )pb")), + EqualsProto(R"pb( + kind_count { key: 3 value: 1 } + kind_samples { + key: 3 + value { + evidence { kind: UNCHECKED_DEREFERENCE location: "foo.cc:42" } + } + } + )pb")); } TEST(MergePartialsTest, BothContainEvidence) { @@ -46,7 +48,10 @@ kind_count { key: 0 value: 2 } kind_samples { key: 0 - value { location: "a" location: "b" } + value { + evidence { kind: ANNOTATED_UNKNOWN location: "a" } + evidence { kind: ANNOTATED_UNKNOWN location: "b" } + } } )pb"); auto R = proto<SlotPartial>( @@ -54,7 +59,11 @@ kind_count { key: 0 value: 2 } kind_samples { key: 0 - value { location: "c" location: "a" location: "d" } + value { + evidence { kind: ANNOTATED_UNKNOWN location: "c" } + evidence { kind: ANNOTATED_UNKNOWN location: "a" } + evidence { kind: ANNOTATED_UNKNOWN location: "d" } + } })pb"); mergePartials(L, R); @@ -64,7 +73,11 @@ kind_count { key: 1 value: 1 } kind_samples { key: 0 - value { location: "a" location: "b" location: "c" } + value { + evidence { kind: ANNOTATED_UNKNOWN location: "a" } + evidence { kind: ANNOTATED_UNKNOWN location: "b" } + evidence { kind: ANNOTATED_UNKNOWN location: "c" } + } } )pb")); } @@ -84,24 +97,25 @@ } TEST(FinalizeTest, ConflictingAnnotations) { - EXPECT_THAT(finalize(proto<SlotPartial>(R"pb( - kind_count { key: 1 value: 1 } # ANNOTATED_NULLABLE - kind_count { key: 2 value: 1 } # ANNOTATED_NONNULL - kind_samples { - key: 1 - value { location: "decl" } - } - kind_samples { - key: 2 - value { location: "def" } - } - )pb")), - EqualsProto(R"pb( - nullability: UNKNOWN - conflict: true - sample_evidence { kind: ANNOTATED_NULLABLE location: "decl" } - sample_evidence { kind: ANNOTATED_NONNULL location: "def" } - )pb")); + EXPECT_THAT( + finalize(proto<SlotPartial>(R"pb( + kind_count { key: 1 value: 1 } # ANNOTATED_NULLABLE + kind_count { key: 2 value: 1 } # ANNOTATED_NONNULL + kind_samples { + key: 1 + value { evidence { kind: ANNOTATED_NULLABLE location: "decl" } } + } + kind_samples { + key: 2 + value { evidence { kind: ANNOTATED_NONNULL location: "def" } } + } + )pb")), + EqualsProto(R"pb( + nullability: UNKNOWN + conflict: true + sample_evidence { kind: ANNOTATED_NULLABLE location: "decl" } + sample_evidence { kind: ANNOTATED_NONNULL location: "def" } + )pb")); } TEST(FinalizeTest, Empty) {
diff --git a/nullability/pointer_nullability_matchers.cc b/nullability/pointer_nullability_matchers.cc index e445b14..f132a11 100644 --- a/nullability/pointer_nullability_matchers.cc +++ b/nullability/pointer_nullability_matchers.cc
@@ -7,7 +7,6 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" -#include "clang/AST/Type.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" #include "llvm/ADT/ArrayRef.h" @@ -62,7 +61,6 @@ using ast_matchers::isInteger; using ast_matchers::isMemberInitializer; using ast_matchers::memberExpr; -using ast_matchers::ofClass; using ast_matchers::parameterCountIs; using ast_matchers::pointee; using ast_matchers::pointerType; @@ -183,6 +181,12 @@ "allocate_shared_for_overwrite")))); } +Matcher<Stmt> isWrapUniqueCall() { + return callExpr( + hasType(isSupportedSmartPointer()), + callee(functionDecl(hasName("WrapUnique"), isInAbslNamespace()))); +} + Matcher<Stmt> isSmartPointerComparisonOpCall() { return cxxOperatorCallExpr( hasAnyOverloadedOperatorName("==", "!="), argumentCountIs(2), @@ -224,4 +228,11 @@ hasDeclaration(decl().bind("member-decl")))))))))))))); } +Matcher<Stmt> isStatusOrValueOrCall() { + return cxxMemberCallExpr( + thisPointerType(qualType(hasCanonicalType(qualType( + hasDeclaration(cxxRecordDecl(hasName("::absl::StatusOr"))))))), + callee(cxxMethodDecl(hasName("value_or")))); +} + } // namespace clang::tidy::nullability
diff --git a/nullability/pointer_nullability_matchers.h b/nullability/pointer_nullability_matchers.h index b09186e..cdbfcf3 100644 --- a/nullability/pointer_nullability_matchers.h +++ b/nullability/pointer_nullability_matchers.h
@@ -6,11 +6,12 @@ #define CRUBIT_NULLABILITY_POINTER_NULLABILITY_MATCHERS_H_ #include "nullability/type_nullability.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/Stmt.h" -#include "clang/AST/Type.h" +#include "clang/AST/TypeBase.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/ASTMatchers/ASTMatchersMacros.h" #include "clang/Basic/LLVM.h" @@ -84,10 +85,12 @@ ast_matchers::internal::Matcher<Stmt> isSmartPointerFreeSwapCall(); ast_matchers::internal::Matcher<Stmt> isSmartPointerBoolConversionCall(); ast_matchers::internal::Matcher<Stmt> isSmartPointerFactoryCall(); +ast_matchers::internal::Matcher<Stmt> isWrapUniqueCall(); ast_matchers::internal::Matcher<Stmt> isSmartPointerComparisonOpCall(); ast_matchers::internal::Matcher<Stmt> isSharedPtrCastCall(); ast_matchers::internal::Matcher<Stmt> isWeakPtrLockCall(); ast_matchers::internal::Matcher<Stmt> isSupportedPointerAccessorCall(); +ast_matchers::internal::Matcher<Stmt> isStatusOrValueOrCall(); AST_MATCHER(Stmt, isNullPointerDefaultInit) { const auto* DefaultInit = dyn_cast<CXXDefaultInitExpr>(&Node); @@ -96,6 +99,37 @@ Builder); } +// Checks if the given declaration is within the `absl` namespace. +// Traverses the parent namespaces up to the top-level namespace. +// For example, `absl::nested::f()` is considered within the `absl` namespace. +// The logic is similar to `isDeclaredInAbseilOrUtil()` in the value transferer: +// https://github.com/google/crubit/blob/55767d191778d2a421a229d3fe446a65912c9865/nullability/value_transferer.cc#L882 +// This is unlike `Decl::isInStdNamespace()` +// (https://clang.llvm.org/doxygen/classclang_1_1Decl.html#a066b012f94431b5bba21d19715a274f4), +// which only traverses up inline namespaces +// (https://en.cppreference.com/w/cpp/language/namespace.html#Inline_namespaces) +// and "transparent contexts" such as those induced by unscoped enums +// (https://clang.llvm.org/doxygen/classclang_1_1DeclContext.html#a1d3b0ef59e3e789890485aa141c4712e). +AST_MATCHER(Decl, isInAbslNamespace) { + const DeclContext* DC = Node.getDeclContext(); + if (DC == nullptr || DC->isTranslationUnit()) { + return false; + } + + // Traverse the parent namespaces up to the top-level namespace. + while (DC->getParent() != nullptr && !DC->getParent()->isTranslationUnit()) { + DC = DC->getParent(); + } + + if (!DC->isNamespace()) { + return false; + } + + const NamespaceDecl* ND = cast<NamespaceDecl>(DC); + const IdentifierInfo* II = ND->getIdentifier(); + return II != nullptr && II->isStr("absl"); +} + } // namespace nullability } // namespace tidy } // namespace clang
diff --git a/nullability/pointer_nullability_matchers_test.cc b/nullability/pointer_nullability_matchers_test.cc index e68f8f3..a76ffc6 100644 --- a/nullability/pointer_nullability_matchers_test.cc +++ b/nullability/pointer_nullability_matchers_test.cc
@@ -5,6 +5,7 @@ #include "nullability/pointer_nullability_matchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Testing/TestAST.h" #include "llvm/ADT/StringRef.h" #include "external/llvm-project/third-party/unittest/googletest/include/gtest/gtest.h" @@ -12,7 +13,20 @@ namespace clang::tidy::nullability { namespace { +using ast_matchers::callee; +using ast_matchers::callExpr; +using ast_matchers::declRefExpr; +using ast_matchers::enumConstantDecl; +using ast_matchers::functionDecl; +using ast_matchers::hasName; using ast_matchers::match; +using ast_matchers::to; + +template <typename MatcherT> +bool matches(llvm::StringRef test_input, MatcherT Matcher) { + TestAST InputAST(test_input.str()); + return !match(Matcher, InputAST.context()).empty(); +} template <typename MatcherT> bool matches(llvm::StringRef base_input, llvm::StringRef test_input, @@ -155,5 +169,199 @@ isSmartPointerBoolConversionCall())); } +TEST(AbslNamespaceTest, MatchesAbslFunctionCall) { + llvm::StringRef Input(R"cc( + namespace absl { + void f() {} + } // namespace absl + )cc"); + auto AbslFunctionCall = + callExpr(callee(functionDecl(isInAbslNamespace(), hasName("f")))); + EXPECT_TRUE(matches(Input, "void target(){ absl::f(); }", AbslFunctionCall)); + EXPECT_TRUE(matches(Input, "using namespace absl; void target(){ f(); }", + AbslFunctionCall)); + EXPECT_TRUE( + matches(Input, "using absl::f; void target(){ f(); }", AbslFunctionCall)); +} + +TEST(AbslNamespaceTest, DoesNotMatchFunctionCallWithNoNamespace) { + llvm::StringRef Input(R"cc( + void f() {} + void target() { f(); } + )cc"); + EXPECT_FALSE(matches(Input, isInAbslNamespace())); +} + +TEST(AbslNamespaceTest, DoesNotMatchFunctionCallWithDifferentNamespace) { + llvm::StringRef Input(R"cc( + namespace util { + void f() {} + } // namespace util + )cc"); + EXPECT_FALSE( + matches(Input, "void target(){ util::f(); }", isInAbslNamespace())); + EXPECT_FALSE(matches(Input, "using namespace util; void target(){ f(); }", + isInAbslNamespace())); + EXPECT_FALSE(matches(Input, "using util::f; void target(){ f(); }", + isInAbslNamespace())); +} + +TEST(AbslNamespaceTest, DoesNotMatchEnumWithAbslType) { + llvm::StringRef Input(R"cc( + enum absl { + kValue, + }; + )cc"); + EXPECT_FALSE( + matches(Input, "void target() { kValue; }", isInAbslNamespace())); + EXPECT_FALSE( + matches(Input, "void target() { absl::kValue; }", isInAbslNamespace())); +} + +TEST(AbslNamespaceTest, DoesNotMatchEnumClassWithQualifiedAbslType) { + llvm::StringRef Input(R"cc( + enum class absl { + kValue, + }; + void target() { absl::kValue; } + )cc"); + EXPECT_FALSE(matches(Input, isInAbslNamespace())); +} + +TEST(AbslNamespaceTest, MatchesEnumInAbslNamespace) { + llvm::StringRef Input(R"cc( + namespace absl { + enum Type { + kValue, + }; + } // namespace absl + )cc"); + EXPECT_TRUE(matches(Input, "void target() { absl::kValue; }", + declRefExpr(to(enumConstantDecl(isInAbslNamespace(), + hasName("kValue")))))); + EXPECT_TRUE(matches(Input, "void target() { absl::Type::kValue; }", + declRefExpr(to(enumConstantDecl(isInAbslNamespace(), + hasName("kValue")))))); +} + +TEST(AbslNamespaceTest, MatchesEnumClassInAbslNamespace) { + llvm::StringRef Input(R"cc( + namespace absl { + enum class Type { + kValue, + }; + void target() { absl::Type::kValue; } + } // namespace absl + )cc"); + EXPECT_TRUE(matches(Input, declRefExpr(to(enumConstantDecl( + isInAbslNamespace(), hasName("kValue")))))); +} + +TEST(AbslNamespaceTest, MatchesFunctionCallWithNestedNamespace) { + llvm::StringRef Input(R"cc( + namespace absl { + namespace nested { + void f() {} + } // namespace nested + } // namespace absl + )cc"); + auto AbslFunctionCall = + callExpr(callee(functionDecl(isInAbslNamespace(), hasName("f")))); + EXPECT_TRUE( + matches(Input, "void target(){ absl::nested::f(); }", AbslFunctionCall)); + EXPECT_TRUE(matches(Input, + "using namespace absl; void target(){ nested::f(); }", + AbslFunctionCall)); + EXPECT_TRUE(matches(Input, + "using namespace absl::nested; void target(){ f(); }", + AbslFunctionCall)); + EXPECT_TRUE(matches(Input, "using absl::nested::f; void target(){ f(); }", + AbslFunctionCall)); +} + +TEST(AbslNamespaceTest, MatchesFunctionCallWithInlineNamespace) { + llvm::StringRef Input(R"cc( + namespace absl { + inline namespace latest { + void f() {} + } // namespace latest + } // namespace absl + )cc"); + auto AbslFunctionCall = + callExpr(callee(functionDecl(isInAbslNamespace(), hasName("f")))); + EXPECT_TRUE(matches(Input, "void target(){ absl::f(); }", AbslFunctionCall)); + EXPECT_TRUE( + matches(Input, "void target(){ absl::latest::f(); }", AbslFunctionCall)); + EXPECT_TRUE(matches(Input, "using namespace absl; void target(){ f(); }", + AbslFunctionCall)); + EXPECT_TRUE(matches(Input, + "using namespace absl; void target(){ latest::f(); }", + AbslFunctionCall)); + EXPECT_TRUE(matches(Input, + "using namespace absl::latest; void target(){ f(); }", + AbslFunctionCall)); + EXPECT_TRUE( + matches(Input, "using absl::f; void target(){ f(); }", AbslFunctionCall)); + EXPECT_TRUE(matches(Input, "using absl::latest::f; void target(){ f(); }", + AbslFunctionCall)); +} + +TEST(AbslNamespaceTest, MatchesFunctionCallWithNestedInlineNamespace) { + llvm::StringRef Input(R"cc( + namespace absl { + inline namespace latest { + inline namespace nested { + void f() {} + } // namespace nested + } // namespace latest + } // namespace absl + )cc"); + auto AbslFunctionCall = + callExpr(callee(functionDecl(isInAbslNamespace(), hasName("f")))); + EXPECT_TRUE(matches(Input, "void target(){ absl::f(); }", AbslFunctionCall)); + EXPECT_TRUE( + matches(Input, "void target(){ absl::latest::f(); }", AbslFunctionCall)); + EXPECT_TRUE(matches(Input, "void target(){ absl::latest::nested::f(); }", + AbslFunctionCall)); +} + +TEST(AbslNamespaceTest, DoesNotMatchFunctionCallWithNestedAbslNamespace) { + llvm::StringRef Input(R"cc( + namespace util { + namespace absl { + void f() {} + } // namespace absl + } // namespace util + )cc"); + EXPECT_FALSE( + matches(Input, "void target(){ util::absl::f(); }", isInAbslNamespace())); + EXPECT_FALSE(matches(Input, + "using namespace util; void target(){ absl::f(); }", + isInAbslNamespace())); + EXPECT_FALSE(matches(Input, + "using namespace util::absl; void target(){ f(); }", + isInAbslNamespace())); +} + +TEST(AbslNamespaceTest, DoesNotMatchFunctionCallWithInlineAbslNamespace) { + llvm::StringRef Input(R"cc( + namespace util { + inline namespace absl { + void f() {} + } // namespace absl + } // namespace util + )cc"); + EXPECT_FALSE( + matches(Input, "void target(){ util::f(); }", isInAbslNamespace())); + EXPECT_FALSE( + matches(Input, "void target(){ util::absl::f(); }", isInAbslNamespace())); + EXPECT_FALSE(matches(Input, + "using namespace util; void target(){ absl::f(); }", + isInAbslNamespace())); + EXPECT_FALSE(matches(Input, + "using namespace util::absl; void target(){ f(); }", + isInAbslNamespace())); +} + } // namespace } // namespace clang::tidy::nullability
diff --git a/nullability/test/nullability_annotations.h b/nullability/test/nullability_annotations.h index ad67498..0157080 100644 --- a/nullability/test/nullability_annotations.h +++ b/nullability/test/nullability_annotations.h
@@ -15,3 +15,4 @@ #define absl_nullable _Nullable #define absl_nonnull _Nonnull #define absl_nullability_unknown _Null_unspecified +#define absl_nullability_conflict _Null_unspecified
diff --git a/nullability/test/smart_pointers.cc b/nullability/test/smart_pointers.cc index 32d288d..5320889 100644 --- a/nullability/test/smart_pointers.cc +++ b/nullability/test/smart_pointers.cc
@@ -414,6 +414,43 @@ nonnull(std::make_unique_for_overwrite<int[]>(5)); } +namespace absl { +template <typename T> +std::unique_ptr<T> WrapUnique(T* P) { + return std::unique_ptr<T>(P); +} +} // namespace absl + +TEST void abslWrapUnique() { + nonnull(absl::WrapUnique(makeNonnullRaw())); + nullable(absl::WrapUnique(makeNullableRaw())); + unknown(absl::WrapUnique(makeUnknownRaw())); +} + +template <typename T> +std::unique_ptr<T> WrapUnique(T* P) { + return std::unique_ptr<T>(P); +} + +TEST void customWrapUnique() { + unknown(WrapUnique(makeNonnullRaw())); + unknown(WrapUnique(makeNullableRaw())); + unknown(WrapUnique(makeUnknownRaw())); +} + +namespace util { +template <typename T> +std::unique_ptr<T> WrapUnique(T* P) { + return std::unique_ptr<T>(P); +} +} // namespace util + +TEST void nonAbslNamespaceWrapUnique() { + unknown(util::WrapUnique(makeNonnullRaw())); + unknown(util::WrapUnique(makeNullableRaw())); + unknown(util::WrapUnique(makeUnknownRaw())); +} + TEST void makeShared() { nonnull(std::make_shared<int>()); nonnull(std::make_shared<int>(42));
diff --git a/nullability/value_transferer.cc b/nullability/value_transferer.cc index 5946368..fe25df0 100644 --- a/nullability/value_transferer.cc +++ b/nullability/value_transferer.cc
@@ -6,6 +6,7 @@ #include <cassert> #include <functional> +#include <optional> #include "absl/base/nullability.h" #include "absl/log/check.h" @@ -40,6 +41,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/Specifiers.h" +#include "llvm/Support/raw_ostream.h" namespace clang::tidy::nullability { using ast_matchers::MatchFinder; @@ -550,6 +552,21 @@ } } +static void transferWrapUniqueCall( + const CallExpr* CE, const MatchFinder::MatchResult& Result, + TransferState<PointerNullabilityLattice>& State) { + if (CE->getNumArgs() != 1) { + return; + } + const Expr* Arg = CE->getArg(0); + RecordStorageLocation& Loc = State.Env.getResultObjectLocation(*CE); + if (isSupportedRawPointerType(Arg->getType()) && + isPointerTypeConvertible(Arg->getType(), + underlyingRawPointerTypeFromSmartPointer(Loc))) { + setSmartPointerValue(Loc, getRawPointerValue(Arg, State.Env), State.Env); + } +} + static void transferSmartPointerComparisonOpCall( const CXXOperatorCallExpr* OpCall, const MatchFinder::MatchResult& Result, TransferState<PointerNullabilityLattice>& State) { @@ -961,6 +978,16 @@ Env.assume(Env.arena().makeEquals(Val->formula(), *IsNull)); } +static bool isMethodOfAbslStatusOr(const FunctionDecl* F) { + const auto* Method = dyn_cast<CXXMethodDecl>(F); + if (!Method) return false; + const CXXRecordDecl* Parent = Method->getParent(); + if (!Parent) return false; + const CXXRecordDecl* CanonicalParent = Parent->getCanonicalDecl(); + if (!CanonicalParent) return false; + return CanonicalParent->getQualifiedNameAsString() == "absl::StatusOr"; +} + static void transferCallExpr(const CallExpr* absl_nonnull CE, const MatchFinder::MatchResult& Result, TransferState<PointerNullabilityLattice>& State) { @@ -969,9 +996,9 @@ // function calls and handle value creation for certain types. const auto* FuncDecl = CE->getDirectCallee(); + const IdentifierInfo* FunII = nullptr; if (FuncDecl != nullptr) { - if (const IdentifierInfo* FunII = - FuncDecl->getDeclName().getAsIdentifierInfo()) { + if ((FunII = FuncDecl->getDeclName().getAsIdentifierInfo())) { if (FunII->isStr("__assert_nullability")) return; // This is part of the implementation of `CHECK_NE`. @@ -1002,9 +1029,9 @@ } } + // Create a pointer value for any supported pointer type so that we can attach + // nullability to it and have the nullability propagate with the pointer. if (isSupportedRawPointerType(CE->getType())) { - // Create a pointer so that we can attach nullability to it and have the - // nullability propagate with the pointer. auto* PointerVal = getRawPointerValue(CE, State.Env); if (!PointerVal) { PointerVal = cast<PointerValue>(State.Env.createValue(CE->getType())); @@ -1018,16 +1045,29 @@ // `Loc` is set iff `CE` is a glvalue, so we know here that it must // be a prvalue. State.Env.setValue(*CE, *PointerVal); + } else if (isSupportedSmartPointerType(CE->getType())) { + if (Loc == nullptr) { + // `CE` must be a prvalue; see above. + Loc = &State.Env.getResultObjectLocation(*CE); + } + StorageLocation& PtrLoc = + cast<RecordStorageLocation>(Loc)->getSyntheticField(PtrField); + auto* Val = State.Env.get<PointerValue>(PtrLoc); + if (Val == nullptr) { + Val = cast<PointerValue>(State.Env.createValue(PtrLoc.getType())); + State.Env.setValue(PtrLoc, *Val); + } + + initPointerFromTypeNullability(*Val, CE, State); } if (CE->isCallToStdMove() || FuncDecl == nullptr) return; // Don't treat parameters of our macro replacement argument-capture functions - // as output parameters. - if (const IdentifierInfo* FunII = - FuncDecl->getDeclName().getAsIdentifierInfo(); - FunII && (FunII->isStr(ArgCaptureAbortIfFalse) || - FunII->isStr(ArgCaptureAbortIfEqual))) + // or of absl::StatusOr::value_or as output parameters. + if (FunII && (FunII->isStr(ArgCaptureAbortIfFalse) || + FunII->isStr(ArgCaptureAbortIfEqual) || + (FunII->isStr("value_or") && isMethodOfAbslStatusOr(FuncDecl)))) return; // Make output parameters (with unknown nullability) initialized to unknown. for (ParamAndArgIterator<CallExpr> Iter(*FuncDecl, *CE); Iter; ++Iter) @@ -1230,6 +1270,111 @@ handleNonConstMemberCall(OCE, RecordLoc, Result, State); } +static void transferStatusOrValueOrCall( + const CXXMemberCallExpr* absl_nonnull MCE, + const MatchFinder::MatchResult& Result, + TransferState<PointerNullabilityLattice>& State) { + // Some overloads are const, some are not. Start with default handling as + // appropriate for constness. Do this first so that the result value will be + // initialized for us; we don't mind that the const method cache is cleared + // before we proceed if this is a non-const call. + if (auto* MethodDecl = MCE->getMethodDecl(); + MethodDecl && !MethodDecl->isConst()) { + transferNonConstMemberCall(MCE, Result, State); + } else { + transferCallExpr(MCE, Result, State); + } + + // absl::StatusOr::value_or can take any argument convertible to the template + // argument type, and claims to return the template argument type. But it + // considers a nullable value or type to be convertible to a nonnull type. + // Rather than warn on an actually non-convertible argument to value_or, we + // model the return value as having the null state of potentially either of + // the argument or the StatusOr's contained pointer, depending on the + // untracked internal state of the StatusOr, and warn on any incompatible + // usage later. + if (!isSupportedPointerType(MCE->getType()) || + // getNumArgs does not count the implicit *this argument. + MCE->getNumArgs() != 1) + return; + Arena& A = State.Env.arena(); + + PointerValue* ResultPV = getPointerValue(MCE, State.Env); + if (!ResultPV) return; + PointerNullState ResultState = getPointerNullState(*ResultPV); + + // Get the null state of the value_or argument. + const Expr* ArgExpr = MCE->getArg(0); + if (!ArgExpr) return; + PointerValue* Arg = getPointerValue(ArgExpr, State.Env); + std::optional<PointerNullState> ArgState; + if (Arg) { + ArgState = getPointerNullState(*Arg); + } else if (ArgExpr->getType()->isNullPtrType() && + isReachableNullptrLiteral(State.Env)) { + ArgState = PointerNullState{.FromNullable = &A.makeLiteral(true), + .IsNull = &A.makeLiteral(true)}; + } else { + // This is never expected to happen, so always log, and assert-fail when + // enabled. + llvm::errs() << "Unable to determine PointerNullState for an argument to " + "absl::StatusOr<SupportedPointerType>::value_or. Please " + "file a bug at <internal link> if you see this.\n"; + assert(false); + return; + } + + // The null state corresponding to the StatusOr's template argument type is + // captured as the current null state of the call's result. Re-assign the null + // state properties of the call's result to be fresh atoms implied by the + // untracked state of the StatusOr, also modeled as a fresh atom, to be equal + // to the null state properties drawn from either the template argument type + // or the value_or argument. + // + // value_or creates copies of the contained pointer or the argument, so only + // the current null states are relevant; we don't need to account for later + // modification of e.g. a referenced decl. + const Formula& StatusOrIsOk = A.makeAtomRef(A.makeAtom()); + DataflowAnalysisContext& DACtx = State.Env.getDataflowAnalysisContext(); + if (ResultState.FromNullable != nullptr) { + if (ArgState->FromNullable == nullptr) { + ResultState.FromNullable = nullptr; + } else { + const Formula& OldResultFromNullable = *ResultState.FromNullable; + ResultState.FromNullable = &A.makeAtomRef(A.makeAtom()); + DACtx.addInvariant(A.makeImplies( + StatusOrIsOk, + A.makeEquals(*ResultState.FromNullable, OldResultFromNullable))); + DACtx.addInvariant(A.makeImplies( + A.makeNot(StatusOrIsOk), + A.makeEquals(*ResultState.FromNullable, *ArgState->FromNullable))); + } + } + if (ResultState.IsNull != nullptr) { + if (ArgState->IsNull == nullptr) { + ResultState.IsNull = nullptr; + } else { + const Formula& OldResultIsNull = *ResultState.IsNull; + ResultState.IsNull = &A.makeAtomRef(A.makeAtom()); + DACtx.addInvariant(A.makeImplies( + StatusOrIsOk, A.makeEquals(*ResultState.IsNull, OldResultIsNull))); + DACtx.addInvariant( + A.makeImplies(A.makeNot(StatusOrIsOk), + A.makeEquals(*ResultState.IsNull, *ArgState->IsNull))); + } + } + + auto& NewPointerVal = + State.Env.create<PointerValue>(ResultPV->getPointeeLoc()); + initPointerNullState(NewPointerVal, DACtx, ResultState); + if (isSupportedRawPointerType(MCE->getType())) { + State.Env.setValue(*MCE, NewPointerVal); + } else if (isSupportedSmartPointerType(MCE->getType())) { + setSmartPointerValue(State.Env.getResultObjectLocation(*MCE), + &NewPointerVal, State.Env); + } +} + dataflow::CFGMatchSwitch<dataflow::TransferState<PointerNullabilityLattice>> buildValueTransferer() { // The value transfer functions must establish: @@ -1269,7 +1414,7 @@ transferSmartPointerMemberSwapCall) .CaseOfCFGStmt<CallExpr>(isSmartPointerFreeSwapCall(), transferSmartPointerFreeSwapCall) - .CaseOfCFGStmt<CXXMemberCallExpr>(isSmartPointerMethodCall("get"), + .CaseOfCFGStmt<CXXMemberCallExpr>(isSmartPointerMethodCall("get", "Get"), transferSmartPointerGetCall) .CaseOfCFGStmt<CXXMemberCallExpr>(isSmartPointerBoolConversionCall(), transferSmartPointerBoolConversionCall) @@ -1279,6 +1424,7 @@ transferSmartPointerOperatorArrow) .CaseOfCFGStmt<CallExpr>(isSmartPointerFactoryCall(), transferSmartPointerFactoryCall) + .CaseOfCFGStmt<CallExpr>(isWrapUniqueCall(), transferWrapUniqueCall) .CaseOfCFGStmt<CXXOperatorCallExpr>(isSmartPointerComparisonOpCall(), transferSmartPointerComparisonOpCall) .CaseOfCFGStmt<CallExpr>(isSharedPtrCastCall(), transferSharedPtrCastCall) @@ -1326,6 +1472,8 @@ CE, getImplicitObjectLocation(*CE, State.Env), State, initCallbackForStorageLocationIfSmartPointer(CE, State.Env)); }) + .CaseOfCFGStmt<CXXMemberCallExpr>(isStatusOrValueOrCall(), + transferStatusOrValueOrCall) .CaseOfCFGStmt<CXXMemberCallExpr>(isZeroParamConstMemberCall(), transferConstMemberCall) .CaseOfCFGStmt<CXXOperatorCallExpr>(isZeroParamConstMemberOperatorCall(),
diff --git a/rs_bindings_from_cc/BUILD b/rs_bindings_from_cc/BUILD index 22181ba..8479678 100644 --- a/rs_bindings_from_cc/BUILD +++ b/rs_bindings_from_cc/BUILD
@@ -40,7 +40,6 @@ deps_for_generated_cc_file = [ "//support/public:bindings_support", "//support:bridge_cpp", - "//support:status_bridge_cpp", ], deps_for_generated_rs_file = [ "//support:ctor", @@ -49,9 +48,9 @@ "//support:bridge_rust", # Required for `Copy` trait assertions added to the generated Rust # code. - "@crate_index//:static_assertions", + "@crate_index//:static_assertions", # v1 # Required for `cxx.rs` integration. - "@crate_index//:cxx", + "@crate_index//:cxx", # v1 ], visibility = ["//:__subpackages__"], ) @@ -236,12 +235,12 @@ "//common:cc_ffi_types", "//common:status_macros", "//common:status_test_matchers", + "//testing/base/public:gunit_main", "@abseil-cpp//absl/flags:flag", "@abseil-cpp//absl/status", "@abseil-cpp//absl/status:statusor", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:string_view", - "@googletest//:gtest_main", ], ) @@ -345,9 +344,9 @@ ":cc_ir", ":ir_from_cc", "//common:status_test_matchers", + "//testing/base/public:gunit_main", "@abseil-cpp//absl/status", "@abseil-cpp//absl/strings", - "@googletest//:gtest_main", ], ) @@ -384,12 +383,12 @@ "//common:code_gen_utils", "//common:crubit_feature", "//common:error_report", - "@crate_index//:flagset", - "@crate_index//:itertools", + "@crate_index//:flagset", # v0_4 + "@crate_index//:itertools", # v0_13 "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:serde", - "@crate_index//:serde_json", + "@crate_index//:quote", # v1 + "@crate_index//:serde", # v1 + "@crate_index//:serde_json", # v1 ], ) @@ -413,8 +412,8 @@ "//common:crubit_feature", "//common:ffi_types", "//common:multiplatform_testing", - "@crate_index//:flagset", - "@crate_index//:itertools", + "@crate_index//:flagset", # v0_4 + "@crate_index//:itertools", # v0_13 ], ) @@ -429,7 +428,7 @@ ":ir_matchers", ":ir_testing", "@crate_index//:googletest", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -487,9 +486,9 @@ "//common:arc_anyhow", "//common:multiplatform_testing", "@crate_index//:googletest", - "@crate_index//:itertools", + "@crate_index//:itertools", # v0_13 "@crate_index//:proc-macro2", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -555,10 +554,10 @@ ":ir_testing", "//common:token_stream_matchers", "//common:token_stream_printer", - "@crate_index//:anyhow", - "@crate_index//:itertools", + "@crate_index//:anyhow", # v1 + "@crate_index//:itertools", # v0_13 "@crate_index//:proc-macro2", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -607,7 +606,7 @@ ":cc_collect_instantiations", "//common:status_test_matchers", "//common:test_utils", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -618,8 +617,8 @@ "//common:arc_anyhow", "//common:ffi_types", "@crate_index//:proc-macro2", - "@crate_index//:serde_json", - "@crate_index//:syn", + "@crate_index//:serde_json", # v1 + "@crate_index//:syn", # v1 ], ) @@ -633,7 +632,7 @@ crate = ":collect_instantiations", deps = [ "@crate_index//:googletest", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -659,10 +658,10 @@ ":cc_ir", ":collect_namespaces", ":ir_from_cc", + "//testing/base/public:gunit_main", "@abseil-cpp//absl/status", "@abseil-cpp//absl/status:statusor", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/types:span", - "@googletest//:gtest_main", ], )
diff --git a/rs_bindings_from_cc/bazel_support/compile_rust.bzl b/rs_bindings_from_cc/bazel_support/compile_rust.bzl index a8eede0..42b1c05 100644 --- a/rs_bindings_from_cc/bazel_support/compile_rust.bzl +++ b/rs_bindings_from_cc/bazel_support/compile_rust.bzl
@@ -91,8 +91,8 @@ type = "rlib", root = src, srcs = depset([src] + extra_srcs), - deps = deps, - proc_macro_deps = depset([]), + deps = deps.to_list(), + proc_macro_deps = [], aliases = {}, output = lib, metadata = rmeta,
diff --git a/rs_bindings_from_cc/cmdline.cc b/rs_bindings_from_cc/cmdline.cc index 36be22a..40ea936 100644 --- a/rs_bindings_from_cc/cmdline.cc +++ b/rs_bindings_from_cc/cmdline.cc
@@ -54,11 +54,13 @@ "`#include \"crubit/support/support_header.h\", specify " "`\"crubit/support/{header}`,"); ABSL_FLAG(std::string, clang_format_exe_path, "", - "Path to a clang-format executable that will be used to format the " + "(optional) Path to a clang-format executable that will be used to " + "format the " ".cc files generated by the tool."); -ABSL_FLAG(std::string, rustfmt_exe_path, "", - "Path to a rustfmt executable that will be used to format the " - ".rs files generated by the tool."); +ABSL_FLAG( + std::string, rustfmt_exe_path, "", + "(optional) Path to a rustfmt executable that will be used to format the " + ".rs files generated by the tool."); ABSL_FLAG(std::string, rustfmt_config_path, "", "(optional) path to a rustfmt.toml file that should replace the " "default formatting of the .rs files generated by the tool."); @@ -267,12 +269,6 @@ if (args.public_headers.empty()) { absl::StrAppend(&error, "please specify --public_headers\n"); } - if (args.clang_format_exe_path.empty()) { - absl::StrAppend(&error, "please specify --clang_format_exe_path\n"); - } - if (args.rustfmt_exe_path.empty()) { - absl::StrAppend(&error, "please specify --rustfmt_exe_path\n"); - } if (args.crubit_support_path_format.empty()) { absl::StrAppend(&error, "please specify --crubit_support_path_format\n");
diff --git a/rs_bindings_from_cc/cmdline_test.cc b/rs_bindings_from_cc/cmdline_test.cc index cad758c..ea3bcb1 100644 --- a/rs_bindings_from_cc/cmdline_test.cc +++ b/rs_bindings_from_cc/cmdline_test.cc
@@ -336,17 +336,13 @@ TEST(CmdlineTest, ClangFormatExePathEmpty) { ASSERT_OK_AND_ASSIGN(CmdlineArgs args, TestCmdlineArgs()); args.clang_format_exe_path = ""; - EXPECT_THAT(Cmdline::Create(std::move(args)), - StatusIs(absl::StatusCode::kInvalidArgument, - HasSubstr("please specify --clang_format_exe_path"))); + EXPECT_OK(Cmdline::Create(std::move(args))); } TEST(CmdlineTest, RustfmtExePathEmpty) { ASSERT_OK_AND_ASSIGN(CmdlineArgs args, TestCmdlineArgs()); args.rustfmt_exe_path = ""; - EXPECT_THAT(Cmdline::Create(std::move(args)), - StatusIs(absl::StatusCode::kInvalidArgument, - HasSubstr("please specify --rustfmt_exe_path"))); + EXPECT_OK(Cmdline::Create(std::move(args))); } TEST(CmdlineTest, SupportPathEmpty) {
diff --git a/rs_bindings_from_cc/generate_bindings/BUILD b/rs_bindings_from_cc/generate_bindings/BUILD index c3a0046..548e481 100644 --- a/rs_bindings_from_cc/generate_bindings/BUILD +++ b/rs_bindings_from_cc/generate_bindings/BUILD
@@ -52,11 +52,11 @@ "//common:token_stream_printer", "//rs_bindings_from_cc:ir", "//rs_bindings_from_cc/generate_bindings/database", - "@crate_index//:flagset", - "@crate_index//:itertools", + "@crate_index//:flagset", # v0_4 + "@crate_index//:itertools", # v0_13 "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:syn", # v1 "@crate_index//:unicode-ident", ], ) @@ -82,9 +82,9 @@ "//rs_bindings_from_cc/generate_bindings/database", "@crate_index//:googletest", "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:static_assertions", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:static_assertions", # v1 + "@crate_index//:syn", # v1 ], ) @@ -101,7 +101,7 @@ "//rs_bindings_from_cc:ir", "//rs_bindings_from_cc/generate_bindings/database", "@crate_index//:proc-macro2", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -122,10 +122,10 @@ "//common:error_report", "//rs_bindings_from_cc:ir", "//rs_bindings_from_cc/generate_bindings/database", - "@crate_index//:flagset", - "@crate_index//:itertools", + "@crate_index//:flagset", # v0_4 + "@crate_index//:itertools", # v0_13 "@crate_index//:proc-macro2", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -153,9 +153,9 @@ "//rs_bindings_from_cc/generate_bindings/database", "@crate_index//:googletest", "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:static_assertions", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:static_assertions", # v1 + "@crate_index//:syn", # v1 ], ) @@ -204,9 +204,9 @@ "//common:ffi_types", "//rs_bindings_from_cc:ir", "//rs_bindings_from_cc/generate_bindings/database", - "@crate_index//:itertools", + "@crate_index//:itertools", # v0_13 "@crate_index//:proc-macro2", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -229,7 +229,7 @@ "//rs_bindings_from_cc:ir_testing", "//rs_bindings_from_cc/generate_bindings/database", "@crate_index//:googletest", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -249,7 +249,7 @@ "//rs_bindings_from_cc:ir", "//rs_bindings_from_cc/generate_bindings/database", "@crate_index//:proc-macro2", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -267,7 +267,7 @@ "//common:arc_anyhow", "//common:token_stream_matchers", "@crate_index//:googletest", - "@crate_index//:quote", + "@crate_index//:quote", # v1 ], ) @@ -287,10 +287,10 @@ "//common:error_report", "//rs_bindings_from_cc:ir", "//rs_bindings_from_cc/generate_bindings/database", - "@crate_index//:itertools", + "@crate_index//:itertools", # v0_13 "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:syn", # v1 "@crate_index//:unicode-ident", ], ) @@ -301,7 +301,7 @@ "generate_function.rs", ], proc_macro_deps = [ - "@crate_index//:rustversion", + "@crate_index//:rustversion", # v1 ], visibility = [ "//rs_bindings_from_cc:__subpackages__", @@ -318,11 +318,11 @@ "//common:errors", "//rs_bindings_from_cc:ir", "//rs_bindings_from_cc/generate_bindings/database", - "@crate_index//:flagset", - "@crate_index//:itertools", + "@crate_index//:flagset", # v0_4 + "@crate_index//:itertools", # v0_13 "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:syn", # v1 ], ) @@ -349,9 +349,9 @@ "//rs_bindings_from_cc:ir_testing", "//rs_bindings_from_cc/generate_bindings/database", "@crate_index//:googletest", - "@crate_index//:quote", - "@crate_index//:static_assertions", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:static_assertions", # v1 + "@crate_index//:syn", # v1 ], ) @@ -368,7 +368,7 @@ "//common:crubit_feature", "//rs_bindings_from_cc:ir", "//rs_bindings_from_cc/generate_bindings/database", - "@crate_index//:heck", + "@crate_index//:heck", # v0_5 ], )
diff --git a/rs_bindings_from_cc/generate_bindings/cpp_type_name.rs b/rs_bindings_from_cc/generate_bindings/cpp_type_name.rs index cc66cd2..452ac7b 100644 --- a/rs_bindings_from_cc/generate_bindings/cpp_type_name.rs +++ b/rs_bindings_from_cc/generate_bindings/cpp_type_name.rs
@@ -124,6 +124,7 @@ RsTypeKind::ExistingRustType(existing_rust_type) => { cpp_type_name_for_item(&Item::ExistingRustType(Rc::clone(existing_rust_type)), ir) } + RsTypeKind::C9Co { original_type, .. } => cpp_type_name_for_record(original_type, ir), } }
diff --git a/rs_bindings_from_cc/generate_bindings/database/BUILD b/rs_bindings_from_cc/generate_bindings/database/BUILD index 3bc3c17..c6b6f99 100644 --- a/rs_bindings_from_cc/generate_bindings/database/BUILD +++ b/rs_bindings_from_cc/generate_bindings/database/BUILD
@@ -30,13 +30,13 @@ "//common:memoized", "//common:token_stream_printer", "//rs_bindings_from_cc:ir", - "@crate_index//:flagset", - "@crate_index//:heck", - "@crate_index//:itertools", + "@crate_index//:flagset", # v0_4 + "@crate_index//:heck", # v0_5 + "@crate_index//:itertools", # v0_13 "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:serde_json", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:serde_json", # v1 + "@crate_index//:syn", # v1 ], )
diff --git a/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs b/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs index 738f7e4..3d52e6d 100644 --- a/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs +++ b/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs
@@ -359,13 +359,12 @@ fn new( db: &dyn BindingsGenerator, template_specialization: Option<&TemplateSpecialization>, - have_reference_param: bool, is_return_type: bool, ) -> Result<Option<Rc<Self>>> { let Some(template_specialization) = template_specialization else { return Ok(None); }; - let type_arg = |template_arg: &TemplateArg, may_bridge: bool| -> Result<RsTypeKind> { + let type_arg = |template_arg: &TemplateArg| -> Result<RsTypeKind> { let arg_type = match &template_arg.type_ { Ok(arg_type) => arg_type.clone(), Err(e) => bail!("{e}"), @@ -373,7 +372,7 @@ // Importantly, `is_return_type` is not propagated through inner types. let arg_type_kind = db.rs_type_kind(arg_type)?; ensure!( - may_bridge || !arg_type_kind.is_bridge_type(), + !arg_type_kind.is_bridge_type(), "Bridge types cannot be used as template arguments" ); // We don't do this in required_crubit_features() because it doesn't know which @@ -391,7 +390,7 @@ ) { ("std::unique_ptr", [t, deleter]) => { let has_std_deleter = is_default_delete(db, t, deleter)?; - let t = type_arg(t, /*may_bridge=*/ false)?; + let t = type_arg(t)?; ensure!(t.is_complete(), "Rust std::unique_ptr<T> cannot be used with incomplete types, and `{}` is incomplete", t.display(db)); ensure!(t.is_destructible(), "Rust std::unique_ptr<T> requires that `T` be destructible, but the destructor of `{}` is non-public or deleted", t.display(db)); if !has_std_deleter { @@ -404,7 +403,7 @@ } ("std::vector", [t, allocator]) => { let has_std_allocator = is_std_allocator(db, t, allocator)?; - let t = type_arg(t, /*may_bridge=*/ false)?; + let t = type_arg(t)?; ensure!(t.is_destructible(), "Rust std::vector<T> requires that `T` be destructible, but the destructor of `{}` is non-public or deleted", t.display(db)); if !has_std_allocator { return Ok(None); @@ -421,7 +420,7 @@ } ("absl::Span", [t]) => { // Revisit the CcType of _t to see if it is const. - let element_type = type_arg(t, /*may_bridge=*/ false)?; + let element_type = type_arg(t)?; let is_const = t.type_.as_ref().expect("should be valid because type_args is the successful result of get_template_args").is_const; Self::AbslSpan { is_const, @@ -444,7 +443,7 @@ // If all else fails, it's some unknown template type. Read any errors from the // template arguments. for t in &template_specialization.template_args { - type_arg(t, /*may_bridge=*/ false)?; + type_arg(t)?; } return Ok(None); } @@ -552,6 +551,39 @@ /// which is used on types like `SliceRef`, `StrRef`, and C++ types generated from Rust /// types by cc_bindings_from_rs. ExistingRustType(Rc<ExistingRustType>), + /// c9::Co<T> + C9Co { + have_reference_param: bool, + result_type: Rc<RsTypeKind>, + original_type: Rc<Record>, + }, +} + +fn new_c9_co_record( + have_reference_param: bool, + record: Rc<Record>, + db: &dyn BindingsGenerator, +) -> Result<Option<RsTypeKind>> { + let Some(ts) = record.template_specialization.as_ref() else { + return Ok(None); + }; + if ts.template_name.as_ref() != "c9::Co" { + return Ok(None); + } + let arg_type = ts.template_args[0] + .type_ + .as_ref() + .map_err(|e: &String| anyhow!("c9::Co T argument is not Crubit compatible: {e}"))? + .clone(); + let arg_type_kind = db.rs_type_kind(arg_type)?; + if let RsTypeKind::Error { error, .. } = arg_type_kind { + return Err(error); + }; + Ok(Some(RsTypeKind::C9Co { + have_reference_param, + result_type: Rc::new(arg_type_kind), + original_type: record, + })) } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -720,6 +752,11 @@ if let Some(bridge_type) = BridgeRsTypeKind::new(&record, db)? { return Ok(RsTypeKind::BridgeType { bridge_type, original_type: record }); } + + if let Some(c9_co) = new_c9_co_record(have_reference_param, Rc::clone(&record), db)? { + return Ok(c9_co); + } + let crate_path = Rc::new(CratePath::new( ir, ir.namespace_qualifier(&record), @@ -729,7 +766,6 @@ uniform_repr_template_type: UniformReprTemplateType::new( db, record.template_specialization.as_ref(), - have_reference_param, is_return_type, )?, record, @@ -818,6 +854,13 @@ matches!(self.unalias(), RsTypeKind::BridgeType { .. }) } + pub fn as_c9_co(&self) -> Option<&RsTypeKind> { + match self.unalias() { + RsTypeKind::C9Co { result_type, .. } => Some(result_type), + _ => None, + } + } + pub fn is_pointer_bridge_type(&self) -> bool { matches!( self.unalias(), @@ -979,6 +1022,7 @@ } } RsTypeKind::ExistingRustType(_) => require_feature(CrubitFeature::Supported, None), + RsTypeKind::C9Co { .. } => require_feature(CrubitFeature::Supported, None), } } (missing_features, reasons.into_iter().join(", ")) @@ -988,6 +1032,11 @@ /// thunks. pub fn is_c_abi_compatible_by_value(&self) -> bool { match self.unalias() { + RsTypeKind::Error { .. } => true, + RsTypeKind::Pointer { .. } => true, + RsTypeKind::Reference { .. } => true, + RsTypeKind::RvalueReference { .. } => true, + RsTypeKind::FuncPtr { .. } => true, RsTypeKind::IncompleteRecord { .. } => { // Incomplete record (forward declaration) as parameter type or return type is // unusual but it's a valid cc_library and such a header can be made to work @@ -1004,9 +1053,12 @@ // TODO(b/274177296): Return `true` for structs where bindings replicate the type of // all the fields. RsTypeKind::Record { .. } => false, + RsTypeKind::Enum { .. } => true, + RsTypeKind::TypeAlias { .. } => unreachable!(), + RsTypeKind::Primitive(_) => true, RsTypeKind::BridgeType { .. } => false, RsTypeKind::ExistingRustType(existing_rust_type) => existing_rust_type.is_same_abi, - _ => true, + RsTypeKind::C9Co { .. } => false, } } @@ -1062,6 +1114,7 @@ RsTypeKind::Primitive(_) => true, RsTypeKind::BridgeType { .. } => false, RsTypeKind::ExistingRustType(_) => true, + RsTypeKind::C9Co { .. } => false, } } @@ -1168,6 +1221,18 @@ BridgeRsTypeKind::StdString { .. } => false, }, RsTypeKind::ExistingRustType(_) => true, + RsTypeKind::C9Co { .. } => false, + } + } + + pub fn is_pointer(&self) -> bool { + matches!(self.unalias(), RsTypeKind::Pointer { .. }) + } + + pub fn is_pointer_to(&self, expected_record: &Record) -> bool { + match self.unalias() { + RsTypeKind::Pointer { pointee, .. } => pointee.is_record(expected_record), + _ => false, } } @@ -1208,6 +1273,10 @@ matches!(self.unalias(), RsTypeKind::Primitive(Primitive::Bool)) } + pub fn is_void(&self) -> bool { + matches!(self.unalias(), RsTypeKind::Primitive(Primitive::Void)) + } + pub fn is_complete(&self) -> bool { !matches!(self.unalias(), RsTypeKind::IncompleteRecord { .. }) } @@ -1480,31 +1549,16 @@ Primitive::Uint64T | Primitive::StdUint64T => quote! { u64 }, }, RsTypeKind::BridgeType { bridge_type, original_type } => { - let make_path = |rust_name: &str| { - let is_absolute_path = rust_name.starts_with("::"); - // If the name starts with "::", then it is an absolute path. In this case, we - // need to skip the first part of the split, since it returns the empty string. - let name_parts = - rust_name.split("::").skip(is_absolute_path as usize).map(make_rs_ident); - let target = - original_type.defining_target().unwrap_or(&original_type.owning_target); - - let prefix = if is_absolute_path { - quote! {} - } else if db.ir().is_current_target(target) { - quote! { crate } - } else { - let ident = make_rs_ident(target.target_name()); - quote! { :: #ident } - }; - quote! { #prefix :: #(#name_parts)::* } - }; match bridge_type { BridgeRsTypeKind::BridgeVoidConverters { rust_name, .. } => { - make_path(rust_name) + fully_qualify_type(db, ir::Item::Record(original_type.clone()), rust_name) } BridgeRsTypeKind::Bridge { rust_name, generic_types, .. } => { - let path = make_path(rust_name); + let path = fully_qualify_type( + db, + ir::Item::Record(original_type.clone()), + rust_name, + ); // If there are no generic types, then we're done. if generic_types.is_empty() { @@ -1515,7 +1569,9 @@ generic_types.iter().map(|t| t.to_token_stream(db)); quote! { #path < #(#generic_types_tokens),* > } } - BridgeRsTypeKind::ProtoMessageBridge { rust_name, .. } => make_path(rust_name), + BridgeRsTypeKind::ProtoMessageBridge { rust_name, .. } => { + fully_qualify_type(db, ir::Item::Record(original_type.clone()), rust_name) + } BridgeRsTypeKind::StdOptional(inner) => { let inner = inner.to_token_stream(db); quote! { ::core::option::Option< #inner > } @@ -1534,13 +1590,117 @@ } } } - RsTypeKind::ExistingRustType(existing_rust_type) => { - existing_rust_type.rs_name.parse().expect("Invalid RsType::name in the IR") + RsTypeKind::ExistingRustType(existing_rust_type) => fully_qualify_type( + db, + ir::Item::ExistingRustType(existing_rust_type.clone()), + &existing_rust_type.rs_name, + ), + RsTypeKind::C9Co { have_reference_param, result_type, .. } => { + let result_type_tokens = if result_type.is_void() { + quote! { () } + } else { + result_type.to_token_stream(db) + }; + // When there are reference parameters, the coroutine must finish before they are + // invalidated (http://shortn/_XPma06AwZh). + match have_reference_param { + false => quote! { ::co::Co<'static, #result_type_tokens> }, + true => quote! { ::co::Co<'_, #result_type_tokens> }, + } } } } } +/// Take a user defined path, like `foo` or `::bar`, and convert it to +/// an absolute path, like `crate::foo` or `::bar` respectively. +/// +/// The path is taken to be relative to crate defining the item. +/// +/// This has _very_ limited support for other type expressions, like `&T`, +/// and special-cases well known builtin types like `char`. +fn fully_qualify_type( + db: &dyn BindingsGenerator, + item: ir::Item, + type_expression: &str, +) -> TokenStream { + let root_crate = || { + let target = item.defining_target().cloned().or_else(|| item.owning_target()).unwrap(); + if db.ir().is_current_target(&target) { + quote! { crate } + } else { + let ident = make_rs_ident(target.target_name()); + quote! { :: #ident } + } + }; + fully_qualify_type_impl(type_expression, root_crate) +} + +/// Broken out for testing :/ +fn fully_qualify_type_impl( + type_expression: &str, + root_crate: impl Fn() -> TokenStream, +) -> TokenStream { + let mut type_expression_suffix = type_expression; + 'fix: loop { + type_expression_suffix = type_expression_suffix.trim_start(); + for prefix in ["&", "*", "const", "mut"] { + if let Some(suffix) = type_expression_suffix.strip_prefix(prefix) { + type_expression_suffix = suffix; + continue 'fix; + } + } + break; + } + + let prefix = &type_expression[..type_expression.len() - type_expression_suffix.len()]; + let prefix: TokenStream = prefix.parse().unwrap(); + + // Primitive types are special-cased. + if matches!( + type_expression_suffix.trim(), + "char" + | "bool" + | "i8" + | "u8" + | "i16" + | "u16" + | "i32" + | "u32" + | "i64" + | "u64" + | "i128" + | "u128" + | "isize" + | "usize" + | "str" + | "f32" + | "f64" + ) { + let suffix: TokenStream = type_expression_suffix.parse().unwrap(); + return quote! { #prefix #suffix }; + } + + // Otherwise, we assume it's a path. + let is_absolute_path = type_expression_suffix.starts_with("::"); + // If the name starts with "::", then it is an absolute path. In this case, we + // need to skip the first part of the split, since it returns the empty string. + // Note: Crubit can generate poorly formatted names, like `:: foo :: bar`, so we also + // need to trim whitespace to create valid identifiers. + let name_parts = type_expression_suffix + .split("::") + .skip(is_absolute_path as usize) + .map(str::trim) + .map(make_rs_ident); + + let top_level_crate = if is_absolute_path { + quote! {} + } else { + root_crate() + }; + quote! { #prefix #top_level_crate :: #(#name_parts)::* } +} + struct RsTypeKindIter<'ty> { todo: Vec<&'ty RsTypeKind>, } @@ -1584,6 +1744,9 @@ BridgeRsTypeKind::StdString { .. } => {} }, RsTypeKind::ExistingRustType(_) => {} + RsTypeKind::C9Co { result_type, .. } => { + self.todo.push(result_type); + } }; Some(curr) } @@ -1615,9 +1778,9 @@ fn test_dfs_iter_ordering_for_func_ptr() { // Set up a test input representing: fn(A, B) -> C let f = { - let a = make_existing_rust_type("A".into(), true); - let b = make_existing_rust_type("B".into(), true); - let c = make_existing_rust_type("C".into(), true); + let a = make_existing_rust_type("::A".into(), true); + let b = make_existing_rust_type("::B".into(), true); + let c = make_existing_rust_type("::C".into(), true); RsTypeKind::FuncPtr { option: false, cc_calling_conv: CcCallingConv::C, @@ -1635,7 +1798,7 @@ _ => unreachable!("Only FuncPtr and ExistingRustType kinds are used in this test"), }) .collect_vec(); - assert_eq!(vec!["fn", "A", "B", "C"], dfs_names); + assert_eq!(vec!["fn", "::A", "::B", "::C"], dfs_names); } struct EmptyDatabase; @@ -1643,18 +1806,18 @@ #[gtest] fn test_lifetime_elision_for_references() { - let referent = Rc::new(make_existing_rust_type("T".into(), true)); + let referent = Rc::new(make_existing_rust_type("::T".into(), true)); let reference = RsTypeKind::Reference { referent, mutability: Mutability::Const, lifetime: Lifetime::new("_"), }; - assert_rs_matches!(reference.to_token_stream(&EmptyDatabase), quote! {&T}); + assert_rs_matches!(reference.to_token_stream(&EmptyDatabase), quote! {&::T}); } #[gtest] fn test_lifetime_elision_for_rvalue_references() { - let referent = Rc::new(make_existing_rust_type("T".into(), true)); + let referent = Rc::new(make_existing_rust_type("::T".into(), true)); let reference = RsTypeKind::RvalueReference { referent, mutability: Mutability::Mut, @@ -1662,13 +1825,13 @@ }; assert_rs_matches!( reference.to_token_stream(&EmptyDatabase), - quote! {RvalueReference<'_, T>} + quote! {RvalueReference<'_, ::T>} ); } #[gtest] fn test_format_as_self_param_rvalue_reference() -> Result<()> { - let referent = Rc::new(make_existing_rust_type("T".into(), true)); + let referent = Rc::new(make_existing_rust_type("::T".into(), true)); let result = RsTypeKind::RvalueReference { referent, mutability: Mutability::Mut, @@ -1682,7 +1845,7 @@ #[gtest] fn test_format_as_self_param_const_rvalue_reference() -> Result<()> { - let referent = Rc::new(make_existing_rust_type("T".into(), true)); + let referent = Rc::new(make_existing_rust_type("::T".into(), true)); let result = RsTypeKind::RvalueReference { referent, mutability: Mutability::Const, @@ -1836,4 +1999,34 @@ expect_that!(void_ptr.allowed_behind_single_element_ptr(), eq(true)); expect_that!(void_ptr.allowed_behind_multi_element_ptr(), eq(false)); } + + #[gtest] + fn test_fully_qualify_type() { + assert_rs_matches!( + fully_qualify_type_impl("A", || { + quote! {crate} + }), + quote! {crate::A}, + ); + } + + #[gtest] + fn test_fully_qualify_i32() { + assert_rs_matches!( + fully_qualify_type_impl("i32", || { + quote! {crate} + }), + quote! {i32}, + ); + } + + #[gtest] + fn test_fully_qualify_ref() { + assert_rs_matches!( + fully_qualify_type_impl("&mut *const X", || { + quote! {crate} + }), + quote! {&mut *const crate::X}, + ); + } }
diff --git a/rs_bindings_from_cc/generate_bindings/generate_function.rs b/rs_bindings_from_cc/generate_bindings/generate_function.rs index bbefc4d..5676e44 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_function.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_function.rs
@@ -573,14 +573,32 @@ } fn api_func_shape_for_identifier( + db: &dyn BindingsGenerator, func: &Func, maybe_record: Option<&Rc<Record>>, param_types: &mut [RsTypeKind], id: &Identifier, - is_unsafe: bool, ) -> (Ident, ImplKind) { + let is_unsafe = match func.safety_annotation { + SafetyAnnotation::Unannotated => { + let mut param_type_iter = param_types.iter(); + if func.cc_name.is_constructor() { + // This is a renamed constructor. + // + // Discard the `this` parameter, as constructors of unsafe types are not + // automatically considered unsafe. Similarly to Rust's raw pointer types, creating + // an unsafe type is safe, but using one is not. + let _ = param_type_iter.next(); + } + param_type_iter.any(|p| db.is_rs_type_kind_unsafe(p.clone())) + } + SafetyAnnotation::Unsafe => true, + SafetyAnnotation::DisableUnsafe => false, + }; + let func_name = make_rs_ident(&id.identifier); let Some(record) = maybe_record else { return (func_name, ImplKind::None { is_unsafe }) }; + let is_renamed_unpin_constructor = func.cc_name.is_constructor() && record.is_unpin(); let format_first_param_as_self = if func.is_instance_method() { let Some(first_param) = param_types.first() else { panic!("Missing `__this` parameter in an instance method: {:?}", func); @@ -589,7 +607,6 @@ } else { false }; - let is_renamed_unpin_constructor = func.cc_name.is_constructor() && record.is_unpin(); ( func_name, ImplKind::Struct { @@ -660,11 +677,75 @@ } } +/// Issue any errors related to unsafe constructors being unsupported. +fn issue_unsafe_constructor_errors( + db: &dyn BindingsGenerator, + func: &Func, + record: &Record, + param_types: &[RsTypeKind], + errors: &Errors, +) { + match func.safety_annotation { + SafetyAnnotation::DisableUnsafe => {} + SafetyAnnotation::Unsafe => { + errors.add(anyhow!( + "Constructors cannot be `unsafe`, but an explicit unsafe annotation was provided. See b/216648347.")); + } + SafetyAnnotation::Unannotated => { + // Move and copy constructors are excepted from this check, as Google C++ style + // disallows move and copy constructors which require invariants to hold on public + // fields of the source object. + let is_move_or_copy_ctor = matches!(param_types, [_this, arg] if arg.is_ref_to(record)); + if is_move_or_copy_ctor { + return; + } + + // TODO: b/452726517 - remove this special case once we infer lifetimes of default + // constructors by default. + let is_lifetimeless_default_ctor = matches!(param_types, [this] if this.is_pointer()); + if is_lifetimeless_default_ctor { + errors + .add(anyhow!("Default constructors do yet receive bindings. See b/452726517.")); + return; + } + + // TODO: b/452726517 - remove this special case once we infer lifetimes of copy and move + // constructors by default. + let is_lifetimeless_move_or_copy_ctor = + matches!(param_types, [_this, arg] if arg.is_pointer_to(record)); + if is_lifetimeless_move_or_copy_ctor { + errors.add(anyhow!( + "Move and copy constructors do yet receive bindings. See b/452726517." + )); + return; + } + + // We skip the first parameter because it's the implicit `this` parameter. + // Constructors of unsafe types are not automatically considered unsafe. + let param_names = func.params.iter().map(|p| &p.identifier); + let unsafe_params = param_names + .zip(param_types) + .skip(1) + .filter(|(_name, p_type)| db.is_rs_type_kind_unsafe((*p_type).clone())) + .map(|(param_name, param_type)| { + format!("\n `{param_name}` of unsafe type `{}`", param_type.display(db)) + }) + .collect::<Vec<String>>() + .join(""); + if !unsafe_params.is_empty() { + errors.add(anyhow!( + "Constructors cannot be `unsafe`, but this constructor accepts:{unsafe_params}" + )); + } + } + } +} + fn api_func_shape_for_constructor( + db: &dyn BindingsGenerator, func: &Func, maybe_record: Option<&Rc<Record>>, param_types: &mut [RsTypeKind], - is_unsafe: bool, errors: &Errors, ) -> Option<(Ident, ImplKind)> { let Some(record) = maybe_record else { @@ -674,6 +755,8 @@ errors.add(err); } materialize_ctor_in_caller(func, param_types); + issue_unsafe_constructor_errors(db, func, record, param_types, errors); + if !record.is_unpin() { let func_name = make_rs_ident("ctor_new"); let [_this, params @ ..] = param_types else { @@ -738,19 +821,6 @@ // generate move constructor bindings explicitly. return None; } - - // TODO(b/216648347): Allow this outside of traits (e.g. after supporting - // translating C++ constructors into static methods in Rust). - // - // Note: move and copy constructors are excepted from this check, as Google C++ style - // disallows move and copy constructors which require invariants to hold on public - // fields of the source object. - if is_unsafe && !param_types[1].is_ref_to(record) { - errors.add(anyhow!( - "Unsafe constructors (e.g. with no elided or explicit lifetimes) \ - are intentionally not supported. See b/216648347." - )); - } let param_type = ¶m_types[1]; let func_name = make_rs_ident("from"); let impl_kind = ImplKind::new_trait( @@ -808,35 +878,18 @@ return None; } - let is_unsafe = match func.safety_annotation { - SafetyAnnotation::Unannotated => { - let mut params_iter = param_types.iter(); - let has_unsafe_self = func.cc_name.is_constructor() - && params_iter - .next() - .map(|this_arg| { - let Some(self_type) = this_arg.referent() else { return false }; - db.is_rs_type_kind_unsafe(self_type.clone()) - }) - .unwrap_or(false); - has_unsafe_self || params_iter.any(|p| db.is_rs_type_kind_unsafe(p.clone())) - } - SafetyAnnotation::Unsafe => true, - SafetyAnnotation::DisableUnsafe => false, - }; - match &func.rs_name { UnqualifiedIdentifier::Operator(op) => { api_func_shape_for_operator(db, func, maybe_record, param_types, op, errors) } UnqualifiedIdentifier::Identifier(id) => { - Some(api_func_shape_for_identifier(func, maybe_record, param_types, id, is_unsafe)) + Some(api_func_shape_for_identifier(db, func, maybe_record, param_types, id)) } UnqualifiedIdentifier::Destructor => { api_func_shape_for_destructor(db, func, maybe_record, param_types) } UnqualifiedIdentifier::Constructor => { - api_func_shape_for_constructor(func, maybe_record, param_types, is_unsafe, errors) + api_func_shape_for_constructor(db, func, maybe_record, param_types, errors) } } } @@ -1047,7 +1100,51 @@ }; return_type.to_token_stream_replacing_by_self(db, record) }; - if return_type.is_crubit_abi_bridge_type() { + if let Some(result_type) = return_type.as_c9_co() { + let consume_result_fn = if result_type.is_void() { + quote! { ::co::internal_crubit::consume_void_result } + } else { + let crubit_abi_type = db.crubit_abi_type(result_type.clone())?; + let crubit_abi_type_tokens = CrubitAbiTypeToRustTokens(&crubit_abi_type); + + // Give the generated Rust API a reference to a monomorphized Rust function + // that knows how to decode this result type. + // + // In theory this might not be necessary with some type erasure and dynamic + // allocation of buffers, but doing it this way is more efficient. + // + // Also in theory we only need to provide A, the Crubit ABI, not A::Size. + // Doing so works around shortcomings in Rust's support for const generics + // being used in const positions: + // + // https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f52065765bba85ea38c09571d80acd0d + // + // Note that the safety of consume_result depends on the correct size being + // passed in. This is not a big deal though because all calls to this + // function are intended to be generated by Crubit, so we don't have to + // worry about folks accidentally doing the wrong thing. + quote! { + ::co::internal_crubit::consume_result:: + <#crubit_abi_type_tokens, { + <#crubit_abi_type_tokens as ::bridge_rust::CrubitAbi>::SIZE + }> + } + }; + quote! { + // TODO(b/274177296): When C structs can be passed by value in function + // pointers, make the thunk just return a CoVtable by value. + let mut __co_vtable_slot = ::co_vtable::c9::internal::rust::CoVtable { + addr: ::core::ptr::null_mut(), + start_coroutine: None, + destroy_at_initial_suspend: None, + }; + #crate_root_path::detail::#thunk_ident( + &raw mut __co_vtable_slot + #( , #clone_prefixes #thunk_args #clone_suffixes )* + ); + ::co::Co::from_raw(__co_vtable_slot, #consume_result_fn) + } + } else if return_type.is_crubit_abi_bridge_type() { let crubit_abi_type = db.crubit_abi_type(return_type.clone())?; let crubit_abi_type_tokens = CrubitAbiTypeToRustTokens(&crubit_abi_type); quote! {
diff --git a/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs b/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs index be4ca74..84bb9ae 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs
@@ -161,6 +161,11 @@ }; out_param = Some(quote! { *mut ::core::ffi::c_void }); out_param_ident = Some(param_idents.next().unwrap().clone()); + } else if return_type.as_c9_co().is_some() { + // Returning a Co involves passing a CoVtable out ptr. + out_param = Some(quote! { *mut ::co_vtable::c9::internal::rust::CoVtable }); + out_param_ident = Some(make_rs_ident("__return_co_vtable")); + return_type_fragment = None; } else if return_type.is_crubit_abi_bridge_type() { out_param = Some(quote! { *mut ::core::ffi::c_uchar }); out_param_ident = Some(make_rs_ident("__return_abi_buffer")); @@ -523,13 +528,16 @@ let is_return_value_c_abi_compatible = return_type_kind.is_c_abi_compatible_by_value(); let return_type_cpp_spelling = cpp_type_name::format_cpp_type(&return_type_kind, ir)?; - let return_type_name = if return_type_kind.is_crubit_abi_bridge_type() { + let return_type_name = if return_type_kind.as_c9_co().is_some() { + param_idents.insert(0, expect_format_cc_ident("__return_co_vtable")); + param_types.insert(0, quote! { c9::internal::rust::CoVtable* }); + quote! {void} + } else if return_type_kind.is_crubit_abi_bridge_type() { param_idents.insert(0, expect_format_cc_ident("__return_abi_buffer")); param_types.insert(0, quote! {unsigned char *}); quote! { void } } else if !is_return_value_c_abi_compatible { param_idents.insert(0, expect_format_cc_ident("__return")); - let return_type_name = cpp_type_name::format_cpp_type(&return_type_kind, ir)?; if let RsTypeKind::BridgeType { bridge_type: BridgeRsTypeKind::BridgeVoidConverters { cpp_to_rust_converter, .. }, .. @@ -541,7 +549,7 @@ }); param_types.insert(0, quote! {void *}); } else { - param_types.insert(0, quote! {#return_type_name *}); + param_types.insert(0, quote! {#return_type_cpp_spelling *}); } quote! {void} } else { @@ -578,7 +586,27 @@ }; let return_expr = quote! {#implementation_function( #( #arg_expressions ),* )}; - let return_stmt = if return_type_kind.is_crubit_abi_bridge_type() { + let return_stmt = if let Some(result_type_kind) = return_type_kind.as_c9_co() { + // The result_type_kind is the T in Co<T> + let start_coroutine = if result_type_kind.is_void() { + // For coroutines that return void, we use the non-templated version. + quote! { &c9::internal::rust::StartCoroutineFromRust } + } else { + let result_type_crubit_abi_type = db.crubit_abi_type(result_type_kind.clone())?; + let result_type_crubit_abi_type_tokens = + CrubitAbiTypeToCppTokens(&result_type_crubit_abi_type); + + // For coroutines that return a non-void value, we use the templated version. + quote! { &c9::internal::rust::StartCoroutineFromRust<#result_type_crubit_abi_type_tokens> } + }; + let out_param = ¶m_idents[0]; + let result_type_cpp_spelling = cpp_type_name::format_cpp_type(result_type_kind, ir)?; + quote! { + #out_param->addr = #return_expr.release_handle(c9::internal::PassKey()).address(); + #out_param->start_coroutine = #start_coroutine; + #out_param->destroy_at_initial_suspend = &c9::internal::rust::DestroyCoroutineFrameFromRust<#result_type_cpp_spelling>; + } + } else if return_type_kind.is_crubit_abi_bridge_type() { let out_param = ¶m_idents[0]; let crubit_abi_type = db.crubit_abi_type(return_type_kind)?; let crubit_abi_type_tokens = CrubitAbiTypeToCppTokens(&crubit_abi_type);
diff --git a/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs b/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs index ecdedc5..57b0587 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs
@@ -358,6 +358,9 @@ ) { return Ok(ApiSnippets::default()); } + if record_rs_type_kind.as_c9_co().is_some() { + return Ok(ApiSnippets::default()); + } if record_rs_type_kind.is_bridge_type() { return Ok(ApiSnippets::default()); }
diff --git a/rs_bindings_from_cc/generate_bindings/has_bindings.rs b/rs_bindings_from_cc/generate_bindings/has_bindings.rs index 0a68905..f91cdc3 100644 --- a/rs_bindings_from_cc/generate_bindings/has_bindings.rs +++ b/rs_bindings_from_cc/generate_bindings/has_bindings.rs
@@ -217,13 +217,7 @@ return; } has_nonunpin = true; - // TODO: b/446717938 - On next binary release, add `"non_unpin_ctor"` to `:wrapper` and - // and then change this to: - // `!enabled_features.contains(crubit_feature::CrubitFeature::NonUnpinCtor)`. - if !enabled_features.is_disjoint( - crubit_feature::CrubitFeature::Wrapper - | crubit_feature::CrubitFeature::NonUnpinCtor, - ) { + if enabled_features.contains(crubit_feature::CrubitFeature::NonUnpinCtor) { return; } let location = location();
diff --git a/rs_bindings_from_cc/generate_bindings/lib.rs b/rs_bindings_from_cc/generate_bindings/lib.rs index 6e6944e..3f56bd2 100644 --- a/rs_bindings_from_cc/generate_bindings/lib.rs +++ b/rs_bindings_from_cc/generate_bindings/lib.rs
@@ -59,16 +59,25 @@ environment, )?; let rs_api = { - let rustfmt_exe_path = Path::new(rustfmt_exe_path); + let rustfmt_exe_path = + if rustfmt_exe_path.is_empty() { None } else { Some(Path::new(rustfmt_exe_path)) }; let rustfmt_config_path = if rustfmt_config_path.is_empty() { None } else { Some(Path::new(rustfmt_config_path)) }; - let rustfmt_config = RustfmtConfig::new(rustfmt_exe_path, rustfmt_config_path); - rs_tokens_to_formatted_string(rs_api, &rustfmt_config)? + let rustfmt_config = + rustfmt_exe_path.map(|path| RustfmtConfig::new(path, rustfmt_config_path)); + rs_tokens_to_formatted_string(rs_api, rustfmt_config.as_ref())? }; - let rs_api_impl = cc_tokens_to_formatted_string(rs_api_impl, Path::new(clang_format_exe_path))?; + let rs_api_impl = { + let clang_format_exe_path = if clang_format_exe_path.is_empty() { + None + } else { + Some(Path::new(clang_format_exe_path)) + }; + cc_tokens_to_formatted_string(rs_api_impl, clang_format_exe_path)? + }; let top_level_comment = generate_top_level_comment(&ir, environment); // TODO(lukasza): Try to remove `#![rustfmt:skip]` - in theory it shouldn't @@ -434,6 +443,10 @@ BridgeRsTypeKind::StdString { .. } => false, }, RsTypeKind::Record { record, .. } => is_record_unsafe(db, &record), + RsTypeKind::C9Co { result_type, .. } => { + // A Co<T> logically produces a T, so it is unsafe iff T is unsafe. + db.is_rs_type_kind_unsafe(result_type.as_ref().clone()) + } } } @@ -495,21 +508,22 @@ "bridge.h".into() }, )); - - // TODO(b/436862191): Remove this once the migration is complete. - if !db - .ir() - .target_crubit_features(&record.owning_target) - .contains(crubit_feature::CrubitFeature::DoNotHardcodeStatusBridge) - && (record.owning_target == "@abseil-cpp//absl/status".into() - || record.owning_target == "@abseil-cpp//absl/status:statusor".into()) - { - internal_includes.insert(CcInclude::SupportLibHeader( - crubit_support_path_format.clone(), - "status_bridge.h".into(), - )); - } } + + if let Ok(rs_type_kind) = db.rs_type_kind((&**record).into()) { + if rs_type_kind.as_c9_co().is_some() { + let includes = [ + "util/c9/internal/rust/co_vtable.h", + "util/c9/internal/rust/destroy_coroutine_frame_from_rust.h", + "util/c9/internal/rust/start_coroutine_from_rust.h", + "util/c9/internal/pass_key.h", + ]; + + for file in includes { + internal_includes.insert(CcInclude::user_header(file.into())); + } + } + }; } for type_alias in ir.type_aliases() {
diff --git a/rs_bindings_from_cc/importers/BUILD b/rs_bindings_from_cc/importers/BUILD index 61147ed..4666cc1 100644 --- a/rs_bindings_from_cc/importers/BUILD +++ b/rs_bindings_from_cc/importers/BUILD
@@ -151,7 +151,10 @@ "//rs_bindings_from_cc:ast_util", "//rs_bindings_from_cc:cc_ir", "//rs_bindings_from_cc:decl_importer", + "@abseil-cpp//absl/algorithm:container", + "@abseil-cpp//absl/log", "@abseil-cpp//absl/log:check", + "@abseil-cpp//absl/strings", "@llvm-project//clang:ast", "@llvm-project//clang:basic", ],
diff --git a/rs_bindings_from_cc/importers/cxx_record.cc b/rs_bindings_from_cc/importers/cxx_record.cc index 3ac2cf3..5110188 100644 --- a/rs_bindings_from_cc/importers/cxx_record.cc +++ b/rs_bindings_from_cc/importers/cxx_record.cc
@@ -519,21 +519,6 @@ } bridge_type = *std::move(builtin_bridge_type); } - - // TODO(b/436862191): Remove this once the migration is complete. - if (!bridge_type.has_value()) { - const clang::CXXRecordDecl* cxx_record_decl = - specialization_decl->getSpecializedTemplate()->getTemplatedDecl(); - if (ictx_.GetOwningTarget(cxx_record_decl) == - BazelLabel("@abseil-cpp//absl/status:statusor") && - cxx_record_decl->getName() == "StatusOr") { - bridge_type = BridgeType{BridgeType::Bridge{ - .rust_name = "::status::absl::StatusOr", - .abi_rust = "::status::absl::StatusOrAbi", - .abi_cpp = "::crubit::StatusOrAbi", - }}; - } - } } else { const clang::NamedDecl* named_decl = record_decl; if (record_decl->getName().empty()) { @@ -561,19 +546,6 @@ } } - // TODO(b/436862191): Remove this once the migration is complete. - if (!bridge_type.has_value()) { - if (ictx_.GetOwningTarget(record_decl) == - BazelLabel("@abseil-cpp//absl/status:status") && - record_decl->getName() == "Status") { - bridge_type = BridgeType{BridgeType::Bridge{ - .rust_name = "absl::Status", - .abi_rust = "absl::StatusAbi", - .abi_cpp = "::crubit::StatusAbi", - }}; - } - } - auto enclosing_item_id = ictx_.GetEnclosingItemId(record_decl); if (!enclosing_item_id.ok()) { return ictx_.ImportUnsupportedItem(
diff --git a/rs_bindings_from_cc/importers/enum.cc b/rs_bindings_from_cc/importers/enum.cc index 1287d75..9ccedc5 100644 --- a/rs_bindings_from_cc/importers/enum.cc +++ b/rs_bindings_from_cc/importers/enum.cc
@@ -111,9 +111,39 @@ } if (ictx_.IsFromProtoTarget(*enum_decl)) { - // TODO(b/406221412): Proto enums aren't at the expected location. - return unsupported( - FormattedError::Static("b/406221412: Proto enums are not supported")); + // Supporting a top-level `Foo_Bar_Baz` enum is hard! It could be any of + // these four things: + // * A top-level `enum Foo_Bar_Baz` + // * A nested `message Foo { enum Bar_Baz }` + // * A differently nested `message Foo_Bar { enum Baz }` + // * A deeply nested `message Foo { message Bar { message Baz } }` + // + // There is no signal on the enum itself to distinguish, so we would need to + // iterate over all the records in the header file to find any aliases that + // refer to this enum, and from that, learn the name. + // + // At least for now, we're going to forgo that exercise. If the name does + // not contain an underscore, then we know it's the first case. + // If the name does contain an underscore, but is retrieved via the alias, + // then we can know the case above perfectly, and can handle this + // in type_alias.cc. But if the name contains an underscore, and is + // accessed at the top level: give up! + if (enum_decl->getName().contains('_')) { + return unsupported(FormattedError::Static( + "b/406221412: Proto enums with underscores are not supported " + "except via Message::Enum syntax.")); + } + ictx_.MarkAsSuccessfullyImported(enum_decl); + return ExistingRustType{ + .rs_name = std::string(enum_decl->getName()), + .cc_name = enum_decl->getQualifiedNameAsString(), + .type_parameters = {}, + .owning_target = ictx_.GetOwningTarget(enum_decl), + .size_align = std::nullopt, + // To be paranoid, assume Rust proto enums are not ABI compatible. + .is_same_abi = false, + .id = ictx_.GenerateItemId(enum_decl), + }; } ictx_.MarkAsSuccessfullyImported(enum_decl);
diff --git a/rs_bindings_from_cc/importers/function.cc b/rs_bindings_from_cc/importers/function.cc index df09b31..31906d7 100644 --- a/rs_bindings_from_cc/importers/function.cc +++ b/rs_bindings_from_cc/importers/function.cc
@@ -589,7 +589,8 @@ clang::isa<clang::OverrideAttr>(attr) || clang::isa<clang::PureAttr>(attr) || clang::isa<clang::ReinitializesAttr>(attr) || - clang::isa<clang::UnusedAttr>(attr)) { + clang::isa<clang::UnusedAttr>(attr) || + clang::isa<clang::AlwaysInlineAttr>(attr)) { // These attributes don't affect Rust. return true; }
diff --git a/rs_bindings_from_cc/importers/type_alias.cc b/rs_bindings_from_cc/importers/type_alias.cc index 53780d5..36e1636 100644 --- a/rs_bindings_from_cc/importers/type_alias.cc +++ b/rs_bindings_from_cc/importers/type_alias.cc
@@ -8,20 +8,78 @@ #include <string> #include <utility> +#include "absl/algorithm/container.h" #include "absl/log/check.h" +#include "absl/log/log.h" +#include "absl/strings/ascii.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" #include "lifetime_annotations/type_lifetimes.h" #include "rs_bindings_from_cc/ast_util.h" #include "rs_bindings_from_cc/ir.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" namespace crubit { +namespace { + +std::string ProtoMessageToRustModName(absl::string_view message_name) { + std::string mod_name = ""; + for (char c : message_name) { + if (absl::ascii_isupper(c) && !mod_name.empty()) { + absl::StrAppend(&mod_name, "_"); + } + // StrAppend doesn't accept `char`. :'( + c = absl::ascii_tolower(static_cast<unsigned char>(c)); + absl::StrAppend(&mod_name, absl::string_view(&c, 1)); + } + return mod_name; +} + +// Returns the relative name of a Rust Proto Enum corresponding to the +// C++ Proto Enum. For example, the C++ enum `MyMessage::MyEnum` would become +// `my_message::MyEnum`. +std::string ProtoEnumToRustName(clang::NamedDecl& decl) { + std::vector<std::string> mod_chain; + for (clang::DeclContext* decl_context = decl.getDeclContext(); + decl_context->isRecord(); decl_context = decl_context->getParent()) { + auto* record_decl = clang::dyn_cast<clang::RecordDecl>(decl_context); + mod_chain.push_back(ProtoMessageToRustModName(record_decl->getName())); + } + absl::c_reverse(mod_chain); + mod_chain.push_back(std::string(decl.getName())); + return absl::StrJoin(mod_chain, "::"); +} +} // namespace std::optional<IR::Item> crubit::TypeAliasImporter::Import( clang::NamedDecl* decl) { + // Special-case proto enums. We handle them under the alias, rather than + // the enum declaration, because the enum declaration gives no useful + // way to obtain the message names that it is a part of unless/until + // `_` is forbidden in enum identifiers. + if (auto* alias_decl = clang::dyn_cast<clang::TypedefNameDecl>(decl)) { + if (ictx_.IsFromProtoTarget(*alias_decl) && + alias_decl->getUnderlyingType()->isEnumeralType()) { + ictx_.MarkAsSuccessfullyImported(decl); + return ExistingRustType{ + .rs_name = ProtoEnumToRustName(*decl), + .cc_name = decl->getQualifiedNameAsString(), + .type_parameters = {}, + .owning_target = ictx_.GetOwningTarget(decl), + .size_align = std::nullopt, + // To be paranoid, assume Rust proto enums are not ABI compatible. + .is_same_abi = false, + .id = ictx_.GenerateItemId(decl), + }; + } + } + clang::DeclContext* decl_context = decl->getDeclContext(); clang::QualType underlying_qualtype; if (auto* typedef_name_decl = clang::dyn_cast<clang::TypedefNameDecl>(decl)) {
diff --git a/rs_bindings_from_cc/test/annotations/do_not_bind_api_impl.cc b/rs_bindings_from_cc/test/annotations/do_not_bind_api_impl.cc index bbb7b62..d39e415 100644 --- a/rs_bindings_from_cc/test/annotations/do_not_bind_api_impl.cc +++ b/rs_bindings_from_cc/test/annotations/do_not_bind_api_impl.cc
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/annotations:do_not_bind -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #include "support/internal/cxx20_backports.h" #include "support/internal/offsetof.h"
diff --git a/rs_bindings_from_cc/test/annotations/do_not_bind_rs_api.rs b/rs_bindings_from_cc/test/annotations/do_not_bind_rs_api.rs index e13105c..b7feaf1 100644 --- a/rs_bindings_from_cc/test/annotations/do_not_bind_rs_api.rs +++ b/rs_bindings_from_cc/test/annotations/do_not_bind_rs_api.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/annotations:do_not_bind -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, negative_impls)] @@ -33,18 +33,19 @@ // Generated from: rs_bindings_from_cc/test/annotations/do_not_bind.h;l=12 // Error while generating bindings for constructor 'ArgumentToBoundOverload::ArgumentToBoundOverload': + // Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::crubit::test::ArgumentToBoundOverload // Expected first reference parameter `__this` to have a lifetime, found *mut crate::crubit::test::ArgumentToBoundOverload // Generated from: rs_bindings_from_cc/test/annotations/do_not_bind.h;l=12 // Error while generating bindings for constructor 'ArgumentToBoundOverload::ArgumentToBoundOverload': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::crubit::test::ArgumentToBoundOverload // Expected first reference parameter `__this` to have a lifetime, found *mut crate::crubit::test::ArgumentToBoundOverload // Generated from: rs_bindings_from_cc/test/annotations/do_not_bind.h;l=12 // Error while generating bindings for constructor 'ArgumentToBoundOverload::ArgumentToBoundOverload': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::crubit::test::ArgumentToBoundOverload // Expected first reference parameter `__this` to have a lifetime, found *mut crate::crubit::test::ArgumentToBoundOverload @@ -72,18 +73,19 @@ // Generated from: rs_bindings_from_cc/test/annotations/do_not_bind.h;l=13 // Error while generating bindings for constructor 'ArgumentToUnboundOverload::ArgumentToUnboundOverload': + // Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::crubit::test::ArgumentToUnboundOverload // Expected first reference parameter `__this` to have a lifetime, found *mut crate::crubit::test::ArgumentToUnboundOverload // Generated from: rs_bindings_from_cc/test/annotations/do_not_bind.h;l=13 // Error while generating bindings for constructor 'ArgumentToUnboundOverload::ArgumentToUnboundOverload': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::crubit::test::ArgumentToUnboundOverload // Expected first reference parameter `__this` to have a lifetime, found *mut crate::crubit::test::ArgumentToUnboundOverload // Generated from: rs_bindings_from_cc/test/annotations/do_not_bind.h;l=13 // Error while generating bindings for constructor 'ArgumentToUnboundOverload::ArgumentToUnboundOverload': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::crubit::test::ArgumentToUnboundOverload // Expected first reference parameter `__this` to have a lifetime, found *mut crate::crubit::test::ArgumentToUnboundOverload @@ -123,13 +125,13 @@ // Generated from: rs_bindings_from_cc/test/annotations/do_not_bind.h;l=26 // Error while generating bindings for constructor 'StructWithDoNotBindConstructor::StructWithDoNotBindConstructor': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::crubit::test::StructWithDoNotBindConstructor // Expected first reference parameter `__this` to have a lifetime, found *mut crate::crubit::test::StructWithDoNotBindConstructor // Generated from: rs_bindings_from_cc/test/annotations/do_not_bind.h;l=26 // Error while generating bindings for constructor 'StructWithDoNotBindConstructor::StructWithDoNotBindConstructor': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::crubit::test::StructWithDoNotBindConstructor // Expected first reference parameter `__this` to have a lifetime, found *mut crate::crubit::test::StructWithDoNotBindConstructor @@ -162,18 +164,19 @@ // Generated from: rs_bindings_from_cc/test/annotations/do_not_bind.h;l=32 // Error while generating bindings for constructor 'StructWithDoNotBindMethod::StructWithDoNotBindMethod': + // Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::crubit::test::StructWithDoNotBindMethod // Expected first reference parameter `__this` to have a lifetime, found *mut crate::crubit::test::StructWithDoNotBindMethod // Generated from: rs_bindings_from_cc/test/annotations/do_not_bind.h;l=32 // Error while generating bindings for constructor 'StructWithDoNotBindMethod::StructWithDoNotBindMethod': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::crubit::test::StructWithDoNotBindMethod // Expected first reference parameter `__this` to have a lifetime, found *mut crate::crubit::test::StructWithDoNotBindMethod // Generated from: rs_bindings_from_cc/test/annotations/do_not_bind.h;l=32 // Error while generating bindings for constructor 'StructWithDoNotBindMethod::StructWithDoNotBindMethod': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::crubit::test::StructWithDoNotBindMethod // Expected first reference parameter `__this` to have a lifetime, found *mut crate::crubit::test::StructWithDoNotBindMethod
diff --git a/rs_bindings_from_cc/test/annotations/rust_name_api_impl.cc b/rs_bindings_from_cc/test/annotations/rust_name_api_impl.cc index a877eea..16d7af6 100644 --- a/rs_bindings_from_cc/test/annotations/rust_name_api_impl.cc +++ b/rs_bindings_from_cc/test/annotations/rust_name_api_impl.cc
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/annotations:rust_name -// Features: infer_operator_lifetimes, std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, infer_operator_lifetimes, std_unique_ptr, std_vector, supported #include "support/internal/cxx20_backports.h" #include "support/internal/offsetof.h"
diff --git a/rs_bindings_from_cc/test/annotations/rust_name_rs_api.rs b/rs_bindings_from_cc/test/annotations/rust_name_rs_api.rs index b8ef68a..09c2df5 100644 --- a/rs_bindings_from_cc/test/annotations/rust_name_rs_api.rs +++ b/rs_bindings_from_cc/test/annotations/rust_name_rs_api.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/annotations:rust_name -// Features: infer_operator_lifetimes, std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, infer_operator_lifetimes, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, negative_impls)]
diff --git a/rs_bindings_from_cc/test/crate_derive/BUILD b/rs_bindings_from_cc/test/crate_derive/BUILD index 9ad02b8..bac112a 100644 --- a/rs_bindings_from_cc/test/crate_derive/BUILD +++ b/rs_bindings_from_cc/test/crate_derive/BUILD
@@ -22,6 +22,6 @@ ], deps = [ "@crate_index//:googletest", - "@crate_index//:static_assertions", + "@crate_index//:static_assertions", # v1 ], )
diff --git a/rs_bindings_from_cc/test/forward_declaration/type_ownership/BUILD b/rs_bindings_from_cc/test/forward_declaration/type_ownership/BUILD index 5ba1ea6..bce049e 100644 --- a/rs_bindings_from_cc/test/forward_declaration/type_ownership/BUILD +++ b/rs_bindings_from_cc/test/forward_declaration/type_ownership/BUILD
@@ -28,7 +28,7 @@ deps = [ ":definition", ":forward_declaration", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/rs_bindings_from_cc/test/function/inline/inline_api_impl.cc b/rs_bindings_from_cc/test/function/inline/inline_api_impl.cc index ee09cd5..4640828 100644 --- a/rs_bindings_from_cc/test/function/inline/inline_api_impl.cc +++ b/rs_bindings_from_cc/test/function/inline/inline_api_impl.cc
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/function/inline:inline -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #include "support/internal/cxx20_backports.h" #include "support/internal/offsetof.h"
diff --git a/rs_bindings_from_cc/test/function/inline/inline_rs_api.rs b/rs_bindings_from_cc/test/function/inline/inline_rs_api.rs index 1ce99c6..bb39301 100644 --- a/rs_bindings_from_cc/test/function/inline/inline_rs_api.rs +++ b/rs_bindings_from_cc/test/function/inline/inline_rs_api.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/function/inline:inline -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, negative_impls)] @@ -40,18 +40,19 @@ // Generated from: rs_bindings_from_cc/test/function/inline/inline.h;l=12 // Error while generating bindings for constructor 'SomeStruct::SomeStruct': +// Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::SomeStruct // Expected first reference parameter `__this` to have a lifetime, found *mut crate::SomeStruct // Generated from: rs_bindings_from_cc/test/function/inline/inline.h;l=12 // Error while generating bindings for constructor 'SomeStruct::SomeStruct': -// Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::SomeStruct // Expected first reference parameter `__this` to have a lifetime, found *mut crate::SomeStruct // Generated from: rs_bindings_from_cc/test/function/inline/inline.h;l=12 // Error while generating bindings for constructor 'SomeStruct::SomeStruct': -// Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::SomeStruct // Expected first reference parameter `__this` to have a lifetime, found *mut crate::SomeStruct
diff --git a/rs_bindings_from_cc/test/function/simple/simple_api_impl.cc b/rs_bindings_from_cc/test/function/simple/simple_api_impl.cc index f3e026c..cf31385 100644 --- a/rs_bindings_from_cc/test/function/simple/simple_api_impl.cc +++ b/rs_bindings_from_cc/test/function/simple/simple_api_impl.cc
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/function/simple:simple -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #include "support/internal/cxx20_backports.h" #include "support/internal/offsetof.h"
diff --git a/rs_bindings_from_cc/test/function/simple/simple_rs_api.rs b/rs_bindings_from_cc/test/function/simple/simple_rs_api.rs index 4693f5b..af618ba 100644 --- a/rs_bindings_from_cc/test/function/simple/simple_rs_api.rs +++ b/rs_bindings_from_cc/test/function/simple/simple_rs_api.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/function/simple:simple -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes)]
diff --git a/rs_bindings_from_cc/test/golden/BUILD b/rs_bindings_from_cc/test/golden/BUILD index 89222b7..c4c9cff 100644 --- a/rs_bindings_from_cc/test/golden/BUILD +++ b/rs_bindings_from_cc/test/golden/BUILD
@@ -51,6 +51,12 @@ "depends_on_nested_types": ["nested_types"], } +# Maps a test to the list of additional aspect hints it needs. +ASPECT_HINTS = { + "nontrivial_type": ["//features:non_unpin_ctor"], + "user_of_unsupported": ["//features:non_unpin_ctor"], +} + TAGS = {} rust_bindings_from_cc_cli_flag( @@ -64,7 +70,7 @@ aspect_hints = [ "//features:infer_operator_lifetimes", ":disable_source_location_in_doc_comment", - ], + ] + (ASPECT_HINTS[name] if name in ASPECT_HINTS else []), deps = [ ((d + "_cc") if d in TESTS else d) for d in (DEPS[name] if name in DEPS else [])
diff --git a/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs b/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs index b58cb36..6d96e32 100644 --- a/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs +++ b/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api.rs
@@ -119,9 +119,20 @@ // Can't generate bindings for Nontrivial::operator=, because of missing required features (<internal link>): // //rs_bindings_from_cc/test/golden:nontrivial_type_cc needs [//features:experimental] for Nontrivial::operator= (return type: references are not supported) -// Error while generating bindings for function 'Nontrivial::operator=': -// Can't generate bindings for Nontrivial::operator=, because of missing required features (<internal link>): -// //rs_bindings_from_cc/test/golden:nontrivial_type_cc needs [//features:non_unpin_ctor] for Nontrivial::operator= (<internal link>_relocatable_error: the return type is not rust-movable) +impl ::ctor::Assign<f32> for Nontrivial { + #[inline(always)] + fn assign<'a>(self: ::core::pin::Pin<&'a mut Self>, __param_0: f32) { + unsafe { + let _ = ::ctor::emplace!(::ctor::FnCtor::new(move |dest: *mut Self| { + crate::detail::__rust_thunk___ZN10NontrivialaSEf( + dest as *mut ::core::ffi::c_void, + self, + __param_0, + ); + })); + } + } +} impl ::ctor::PinnedDrop for Nontrivial { #[inline(always)] @@ -446,15 +457,33 @@ } } -// Error while generating bindings for function 'TakesByValue': -// Can't generate bindings for TakesByValue, because of missing required features (<internal link>): -// //rs_bindings_from_cc/test/golden:nontrivial_type_cc needs [//features:non_unpin_ctor] for TakesByValue (<internal link>_relocatable_error: the return type is not rust-movable) -// //rs_bindings_from_cc/test/golden:nontrivial_type_cc needs [//features:non_unpin_ctor] for TakesByValue (<internal link>_relocatable_error: nontrivial (parameter #0) is not rust-movable) +#[inline(always)] +pub fn TakesByValue( + nontrivial: impl ::ctor::Ctor<Output = crate::Nontrivial, Error = ::ctor::Infallible>, +) -> impl ::ctor::Ctor<Output = crate::Nontrivial, Error = ::ctor::Infallible> { + unsafe { + ::ctor::FnCtor::new(move |dest: *mut crate::Nontrivial| { + crate::detail::__rust_thunk___Z12TakesByValue10Nontrivial( + dest as *mut ::core::ffi::c_void, + ::core::pin::Pin::into_inner_unchecked(::ctor::emplace!(nontrivial)), + ); + }) + } +} -// Error while generating bindings for function 'TakesByValueInline': -// Can't generate bindings for TakesByValueInline, because of missing required features (<internal link>): -// //rs_bindings_from_cc/test/golden:nontrivial_type_cc needs [//features:non_unpin_ctor] for TakesByValueInline (<internal link>_relocatable_error: the return type is not rust-movable) -// //rs_bindings_from_cc/test/golden:nontrivial_type_cc needs [//features:non_unpin_ctor] for TakesByValueInline (<internal link>_relocatable_error: nontrivial (parameter #0) is not rust-movable) +#[inline(always)] +pub fn TakesByValueInline( + nontrivial: impl ::ctor::Ctor<Output = crate::NontrivialInline, Error = ::ctor::Infallible>, +) -> impl ::ctor::Ctor<Output = crate::NontrivialInline, Error = ::ctor::Infallible> { + unsafe { + ::ctor::FnCtor::new(move |dest: *mut crate::NontrivialInline| { + crate::detail::__rust_thunk___Z18TakesByValueInline16NontrivialInline( + dest as *mut ::core::ffi::c_void, + ::core::pin::Pin::into_inner_unchecked(::ctor::emplace!(nontrivial)), + ); + }) + } +} #[inline(always)] pub fn TakesByValueUnpin(mut nontrivial: crate::NontrivialUnpin) -> crate::NontrivialUnpin { @@ -540,9 +569,22 @@ // //rs_bindings_from_cc/test/golden:nontrivial_type_cc needs [//features:experimental] for NontrivialByValue::operator= (return type: references are not supported) // //rs_bindings_from_cc/test/golden:nontrivial_type_cc needs [//features:experimental] for NontrivialByValue::operator= (the type of other (parameter #1): references are not supported) -// Error while generating bindings for function 'NontrivialByValue::operator=': -// Can't generate bindings for NontrivialByValue::operator=, because of missing required features (<internal link>): -// //rs_bindings_from_cc/test/golden:nontrivial_type_cc needs [//features:non_unpin_ctor] for NontrivialByValue::operator= (<internal link>_relocatable_error: other (parameter #1) is not rust-movable) +impl<'other> ::ctor::UnpinAssign<::ctor::RvalueReference<'other, crate::Nontrivial>> + for NontrivialByValue +{ + #[inline(always)] + fn unpin_assign<'a>(&'a mut self, other: ::ctor::RvalueReference<'other, crate::Nontrivial>) { + unsafe { + let mut __return = ::core::mem::MaybeUninit::<Self>::uninit(); + crate::detail::__rust_thunk___ZN17NontrivialByValueaSE10Nontrivial( + &raw mut __return as *mut ::core::ffi::c_void, + self, + other, + ); + __return.assume_init(); + } + } +} #[diagnostic::on_unimplemented( message = "binding generation for function failed\nExpected first operator== param reference to be immutable, but found mutable reference: &'a mut crate::NontrivialByValue\ncomparison operator return type must be `bool`, found: crate::NontrivialByValue" @@ -603,13 +645,34 @@ } } -// Error while generating bindings for function 'TakesNonmovableByValue': -// Can't generate bindings for TakesNonmovableByValue, because of missing required features (<internal link>): -// //rs_bindings_from_cc/test/golden:nontrivial_type_cc needs [//features:non_unpin_ctor] for TakesNonmovableByValue (<internal link>_relocatable_error: nonmovable (parameter #0) is not rust-movable) +#[diagnostic::on_unimplemented( + message = "binding generation for function failed\nNon-movable, non-trivial_abi type 'crate::Nonmovable' is not supported by value as parameter #0" +)] +pub trait BindingFailedFor_Z22TakesNonmovableByValue10Nonmovable {} +#[inline(always)] +pub fn TakesNonmovableByValue<'error>( + nonmovable: impl ::ctor::Ctor<Output = crate::Nonmovable, Error = ::ctor::Infallible>, +) where + &'error (): BindingFailedFor_Z22TakesNonmovableByValue10Nonmovable, +{ + #![allow(unused_variables)] + unreachable!( + "This impl can never be instantiated. \ + If this message appears at runtime, please report a <internal link>." + ) +} -// Error while generating bindings for function 'ReturnsNonmovableByValue': -// Can't generate bindings for ReturnsNonmovableByValue, because of missing required features (<internal link>): -// //rs_bindings_from_cc/test/golden:nontrivial_type_cc needs [//features:non_unpin_ctor] for ReturnsNonmovableByValue (<internal link>_relocatable_error: the return type is not rust-movable) +#[inline(always)] +pub fn ReturnsNonmovableByValue( +) -> impl ::ctor::Ctor<Output = crate::Nonmovable, Error = ::ctor::Infallible> { + unsafe { + ::ctor::FnCtor::new(move |dest: *mut crate::Nonmovable| { + crate::detail::__rust_thunk___Z24ReturnsNonmovableByValuev( + dest as *mut ::core::ffi::c_void, + ); + }) + } +} mod detail { #[allow(unused_imports)] @@ -628,6 +691,11 @@ field: ::core::ffi::c_int, unused: ::core::ffi::c_int, ); + pub(crate) unsafe fn __rust_thunk___ZN10NontrivialaSEf<'a>( + __return: *mut ::core::ffi::c_void, + __this: ::core::pin::Pin<&'a mut crate::Nontrivial>, + __param_0: f32, + ); #[link_name = "_ZN10NontrivialD1Ev"] pub(crate) unsafe fn __rust_thunk___ZN10NontrivialD1Ev<'a>( __this: ::core::pin::Pin<&'a mut crate::Nontrivial>, @@ -689,10 +757,23 @@ pub(crate) unsafe fn __rust_thunk___ZN15NontrivialUnpin14MemberFunctionEv<'a>( __this: &'a mut crate::NontrivialUnpin, ); + pub(crate) unsafe fn __rust_thunk___Z12TakesByValue10Nontrivial( + __return: *mut ::core::ffi::c_void, + nontrivial: &mut crate::Nontrivial, + ); + pub(crate) unsafe fn __rust_thunk___Z18TakesByValueInline16NontrivialInline( + __return: *mut ::core::ffi::c_void, + nontrivial: &mut crate::NontrivialInline, + ); pub(crate) unsafe fn __rust_thunk___Z17TakesByValueUnpin15NontrivialUnpin( __return: *mut ::core::ffi::c_void, nontrivial: &mut crate::NontrivialUnpin, ); + pub(crate) unsafe fn __rust_thunk___ZN17NontrivialByValueaSE10Nontrivial<'a, 'other>( + __return: *mut ::core::ffi::c_void, + __this: &'a mut crate::NontrivialByValue, + other: ::ctor::RvalueReference<'other, crate::Nontrivial>, + ); #[link_name = "_ZN10NonmovableC1Ev"] pub(crate) unsafe fn __rust_thunk___ZN10NonmovableC1Ev(__this: *mut ::core::ffi::c_void); #[link_name = "_ZN10NonmovableD1Ev"] @@ -703,6 +784,9 @@ pub(crate) unsafe fn __rust_thunk___ZN10Nonmovable14MemberFunctionEv<'a>( __this: ::core::pin::Pin<&'a mut crate::Nonmovable>, ); + pub(crate) unsafe fn __rust_thunk___Z24ReturnsNonmovableByValuev( + __return: *mut ::core::ffi::c_void, + ); } }
diff --git a/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api_impl.cc b/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api_impl.cc index 63966da..67497b1 100644 --- a/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api_impl.cc +++ b/rs_bindings_from_cc/test/golden/nontrivial_type_rs_api_impl.cc
@@ -22,6 +22,12 @@ static_assert(alignof(struct Nontrivial) == 4); static_assert(CRUBIT_OFFSET_OF(field, struct Nontrivial) == 0); +extern "C" void __rust_thunk___ZN10NontrivialaSEf(struct Nontrivial* __return, + struct Nontrivial* __this, + float __param_0) { + new (__return) auto(__this->operator=(__param_0)); +} + static_assert((void (::Nontrivial::*)())&Nontrivial::Unqualified); static_assert((void (::Nontrivial::*)() const) & Nontrivial::ConstQualified); @@ -84,6 +90,21 @@ static_assert((void (::NontrivialUnpin::*)())&NontrivialUnpin::MemberFunction); +extern "C" void __rust_thunk___Z12TakesByValue10Nontrivial( + struct Nontrivial* __return, struct Nontrivial* nontrivial) { + new (__return) auto(TakesByValue(std::move(*nontrivial))); +} + +static_assert((struct Nontrivial (*)(struct Nontrivial))&TakesByValue); + +extern "C" void __rust_thunk___Z18TakesByValueInline16NontrivialInline( + struct NontrivialInline* __return, struct NontrivialInline* nontrivial) { + new (__return) auto(TakesByValueInline(std::move(*nontrivial))); +} + +static_assert( + (struct NontrivialInline (*)(struct NontrivialInline))&TakesByValueInline); + extern "C" void __rust_thunk___Z17TakesByValueUnpin15NontrivialUnpin( struct NontrivialUnpin* __return, struct NontrivialUnpin* nontrivial) { new (__return) auto(TakesByValueUnpin(std::move(*nontrivial))); @@ -95,9 +116,22 @@ static_assert(sizeof(struct NontrivialByValue) == 1); static_assert(alignof(struct NontrivialByValue) == 1); +extern "C" void __rust_thunk___ZN17NontrivialByValueaSE10Nontrivial( + struct NontrivialByValue* __return, struct NontrivialByValue* __this, + struct Nontrivial* other) { + new (__return) auto(__this->operator=(std::move(*other))); +} + static_assert(sizeof(struct Nonmovable) == 1); static_assert(alignof(struct Nonmovable) == 1); static_assert((void (::Nonmovable::*)())&Nonmovable::MemberFunction); +extern "C" void __rust_thunk___Z24ReturnsNonmovableByValuev( + struct Nonmovable* __return) { + new (__return) auto(ReturnsNonmovableByValue()); +} + +static_assert((struct Nonmovable (*)())&ReturnsNonmovableByValue); + #pragma clang diagnostic pop
diff --git a/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs b/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs index 7daaa4b..b8ddc5a 100644 --- a/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs +++ b/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api.rs
@@ -6,7 +6,7 @@ // //rs_bindings_from_cc/test/golden:user_of_unsupported_cc #![rustfmt::skip] -#![feature(allocator_api, cfg_sanitize, custom_inner_attributes)] +#![feature(allocator_api, cfg_sanitize, custom_inner_attributes, impl_trait_in_assoc_type)] #![allow(stable_features)] #![no_std] #![allow(improper_ctypes)] @@ -14,6 +14,26 @@ #![allow(dead_code, unused_mut)] #![deny(warnings)] -// Error while generating bindings for function 'UseNontrivialCustomType': -// Can't generate bindings for UseNontrivialCustomType, because of missing required features (<internal link>): -// //rs_bindings_from_cc/test/golden:user_of_unsupported_cc needs [//features:non_unpin_ctor] for UseNontrivialCustomType (<internal link>_relocatable_error: non_trivial_custom_type (parameter #0) is not rust-movable) +#[inline(always)] +pub fn UseNontrivialCustomType( + non_trivial_custom_type: impl ::ctor::Ctor< + Output = unsupported_cc::NontrivialCustomType, + Error = ::ctor::Infallible, + >, +) { + unsafe { + crate::detail::__rust_thunk___Z23UseNontrivialCustomType20NontrivialCustomType( + ::core::pin::Pin::into_inner_unchecked(::ctor::emplace!(non_trivial_custom_type)), + ) + } +} + +mod detail { + #[allow(unused_imports)] + use super::*; + unsafe extern "C" { + pub(crate) unsafe fn __rust_thunk___Z23UseNontrivialCustomType20NontrivialCustomType( + non_trivial_custom_type: &mut unsupported_cc::NontrivialCustomType, + ); + } +}
diff --git a/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api_impl.cc b/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api_impl.cc index a534a06..81baec6 100644 --- a/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api_impl.cc +++ b/rs_bindings_from_cc/test/golden/user_of_unsupported_rs_api_impl.cc
@@ -18,4 +18,11 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wthread-safety-analysis" +extern "C" void __rust_thunk___Z23UseNontrivialCustomType20NontrivialCustomType( + struct NontrivialCustomType* non_trivial_custom_type) { + UseNontrivialCustomType(std::move(*non_trivial_custom_type)); +} + +static_assert((void (*)(struct NontrivialCustomType))&UseNontrivialCustomType); + #pragma clang diagnostic pop
diff --git a/rs_bindings_from_cc/test/namespace/inline/inline_api_impl.cc b/rs_bindings_from_cc/test/namespace/inline/inline_api_impl.cc index 2657914..9e07fd3 100644 --- a/rs_bindings_from_cc/test/namespace/inline/inline_api_impl.cc +++ b/rs_bindings_from_cc/test/namespace/inline/inline_api_impl.cc
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/namespace/inline:inline -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #include "support/internal/cxx20_backports.h" #include "support/internal/offsetof.h"
diff --git a/rs_bindings_from_cc/test/namespace/inline/inline_rs_api.rs b/rs_bindings_from_cc/test/namespace/inline/inline_rs_api.rs index fb71812..6e97dc0 100644 --- a/rs_bindings_from_cc/test/namespace/inline/inline_rs_api.rs +++ b/rs_bindings_from_cc/test/namespace/inline/inline_rs_api.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/namespace/inline:inline -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, negative_impls)] @@ -38,18 +38,19 @@ // Generated from: rs_bindings_from_cc/test/namespace/inline/inline.h;l=11 // Error while generating bindings for constructor 'MyStruct::MyStruct': + // Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::foo::inline1::MyStruct // Expected first reference parameter `__this` to have a lifetime, found *mut crate::foo::inline1::MyStruct // Generated from: rs_bindings_from_cc/test/namespace/inline/inline.h;l=11 // Error while generating bindings for constructor 'MyStruct::MyStruct': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::foo::inline1::MyStruct // Expected first reference parameter `__this` to have a lifetime, found *mut crate::foo::inline1::MyStruct // Generated from: rs_bindings_from_cc/test/namespace/inline/inline.h;l=11 // Error while generating bindings for constructor 'MyStruct::MyStruct': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::foo::inline1::MyStruct // Expected first reference parameter `__this` to have a lifetime, found *mut crate::foo::inline1::MyStruct
diff --git a/rs_bindings_from_cc/test/references/references_api_impl.cc b/rs_bindings_from_cc/test/references/references_api_impl.cc index 508b688..5631cb6 100644 --- a/rs_bindings_from_cc/test/references/references_api_impl.cc +++ b/rs_bindings_from_cc/test/references/references_api_impl.cc
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/references:references -// Features: infer_operator_lifetimes, std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, infer_operator_lifetimes, std_unique_ptr, std_vector, supported #include "support/internal/cxx20_backports.h" #include "support/internal/offsetof.h"
diff --git a/rs_bindings_from_cc/test/references/references_rs_api.rs b/rs_bindings_from_cc/test/references/references_rs_api.rs index 4022196..4252e97 100644 --- a/rs_bindings_from_cc/test/references/references_rs_api.rs +++ b/rs_bindings_from_cc/test/references/references_rs_api.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/references:references -// Features: infer_operator_lifetimes, std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, infer_operator_lifetimes, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, negative_impls)] @@ -30,7 +30,7 @@ } #[diagnostic::on_unimplemented( - message = "binding generation for function failed\nUnsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347." + message = "binding generation for function failed\nConstructors cannot be `unsafe`, but this constructor accepts:\n `ptr` of unsafe type `*mut::core::ffi::c_int`" )] pub trait BindingFailedFor_ZN22TypeWithPtrConstructorC1EPi {} /// Generated from: rs_bindings_from_cc/test/references/references.h;l=10 @@ -63,7 +63,7 @@ } #[diagnostic::on_unimplemented( - message = "binding generation for function failed\nUnsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347." + message = "binding generation for function failed\nConstructors cannot be `unsafe`, but this constructor accepts:\n `ptr` of unsafe type `*mut::core::ffi::c_int`" )] pub trait BindingFailedFor_ZN29TypeWithNonNullPtrConstructorC1EPi {} /// Generated from: rs_bindings_from_cc/test/references/references.h;l=15
diff --git a/rs_bindings_from_cc/test/rs_bindings_from_cc_test.sh b/rs_bindings_from_cc/test/rs_bindings_from_cc_test.sh index e3a2101..cf365d9 100755 --- a/rs_bindings_from_cc/test/rs_bindings_from_cc_test.sh +++ b/rs_bindings_from_cc/test/rs_bindings_from_cc_test.sh
@@ -44,25 +44,6 @@ --target=//:target \ --rs_out=\"${rs_out}\" \ --cc_out=\"${cc_out}\" 2>&1 \ - --crubit_support_path_format=\"<test/crubit/support/path/{header}>\" | \ - grep 'please specify --clang_format_exe_path' > /dev/null" \ - "generator should show help message for --clang_format_exe_path" - - EXPECT_SUCCEED \ - "\"${RS_BINDINGS_FROM_CC}\" \ - --target=//:target \ - --rs_out=\"${rs_out}\" \ - --cc_out=\"${cc_out}\" 2>&1 \ - --crubit_support_path_format=\"<test/crubit/support/path/{header}>\" \ - --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" | \ - grep 'please specify --rustfmt_exe_path' > /dev/null" \ - "generator should show help message for --rustfmt_exe_path" - - EXPECT_SUCCEED \ - "\"${RS_BINDINGS_FROM_CC}\" \ - --target=//:target \ - --rs_out=\"${rs_out}\" \ - --cc_out=\"${cc_out}\" 2>&1 \ --crubit_support_path_format=\"<test/crubit/support/path/{header}>\" \ --clang_format_exe_path=\"${DEFAULT_CLANG_FORMAT_EXE_PATH}\" \ --rustfmt_exe_path=\"${DEFAULT_RUSTFMT_EXE_PATH}\" | \ @@ -105,6 +86,30 @@ EXPECT_FILE_NOT_EMPTY "${cc_out}" } +function test::optional_formatting_paths() { + local rs_out="${TEST_TMPDIR}/rs_api.rs" + local cc_out="${TEST_TMPDIR}/rs_api_impl.cc" + local hdr="no_such_file.h" + local json + json="$(cat <<-EOT + [{"t": "//foo/bar:baz", "h": ["${hdr}"], "f": ["experimental", "supported"]}] +EOT +)" + + EXPECT_SUCCEED \ + "\"${RS_BINDINGS_FROM_CC}\" \ + --target=//:target \ + --rs_out=\"${rs_out}\" \ + --cc_out=\"${cc_out}\" 2>&1 \ + --crubit_support_path_format=\"<test/crubit/support/path/{header}>\" \ + --public_headers=\"${hdr}\" \ + --target_args=\"$(echo "${json}" | quote_escape)\" \ + --do_nothing" + + EXPECT_FILE_NOT_EMPTY "${rs_out}" + EXPECT_FILE_NOT_EMPTY "${cc_out}" +} + function test::do_nothing() { local rs_out="${TEST_TMPDIR}/rs_api.rs" local cc_out="${TEST_TMPDIR}/rs_api_impl.cc"
diff --git a/rs_bindings_from_cc/test/struct/constructors/BUILD b/rs_bindings_from_cc/test/struct/constructors/BUILD index 7bd416e..196042f 100644 --- a/rs_bindings_from_cc/test/struct/constructors/BUILD +++ b/rs_bindings_from_cc/test/struct/constructors/BUILD
@@ -22,6 +22,6 @@ deps = [ "//support:ctor", "@crate_index//:googletest", - "@crate_index//:static_assertions", + "@crate_index//:static_assertions", # v1 ], )
diff --git a/rs_bindings_from_cc/test/struct/default_member_functions/BUILD b/rs_bindings_from_cc/test/struct/default_member_functions/BUILD index 8b3693a..4be842e 100644 --- a/rs_bindings_from_cc/test/struct/default_member_functions/BUILD +++ b/rs_bindings_from_cc/test/struct/default_member_functions/BUILD
@@ -22,6 +22,6 @@ deps = [ "//support:ctor", "@crate_index//:googletest", - "@crate_index//:static_assertions", + "@crate_index//:static_assertions", # v1 ], )
diff --git a/rs_bindings_from_cc/test/struct/destructors/destructors_api_impl.cc b/rs_bindings_from_cc/test/struct/destructors/destructors_api_impl.cc index e203e3d..25b3ae0 100644 --- a/rs_bindings_from_cc/test/struct/destructors/destructors_api_impl.cc +++ b/rs_bindings_from_cc/test/struct/destructors/destructors_api_impl.cc
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/struct/destructors:destructors -// Features: infer_operator_lifetimes, std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, infer_operator_lifetimes, std_unique_ptr, std_vector, supported #include "support/internal/cxx20_backports.h" #include "support/internal/offsetof.h"
diff --git a/rs_bindings_from_cc/test/struct/destructors/destructors_rs_api.rs b/rs_bindings_from_cc/test/struct/destructors/destructors_rs_api.rs index ae4d0ea..28ff665 100644 --- a/rs_bindings_from_cc/test/struct/destructors/destructors_rs_api.rs +++ b/rs_bindings_from_cc/test/struct/destructors/destructors_rs_api.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/struct/destructors:destructors -// Features: infer_operator_lifetimes, std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, infer_operator_lifetimes, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, negative_impls)]
diff --git a/rs_bindings_from_cc/test/struct/forward_declarations/BUILD b/rs_bindings_from_cc/test/struct/forward_declarations/BUILD index 95eacf4..e69bd59 100644 --- a/rs_bindings_from_cc/test/struct/forward_declarations/BUILD +++ b/rs_bindings_from_cc/test/struct/forward_declarations/BUILD
@@ -56,6 +56,6 @@ "//support:ctor", "//support:forward_declare", "@crate_index//:googletest", - "@crate_index//:static_assertions", + "@crate_index//:static_assertions", # v1 ], )
diff --git a/rs_bindings_from_cc/test/struct/nonunpin/BUILD b/rs_bindings_from_cc/test/struct/nonunpin/BUILD index f08404d..9784ee2 100644 --- a/rs_bindings_from_cc/test/struct/nonunpin/BUILD +++ b/rs_bindings_from_cc/test/struct/nonunpin/BUILD
@@ -8,7 +8,7 @@ crubit_test_cc_library( name = "nonunpin", hdrs = ["nonunpin.h"], - aspect_hints = ["//features:experimental"], + aspect_hints = ["//features:non_unpin_ctor"], deps = ["@abseil-cpp//absl/log:check"], ) @@ -24,3 +24,23 @@ "@crate_index//:googletest", ], ) + +crubit_test_cc_library( + name = "nonunpin_experimental", + hdrs = ["nonunpin.h"], + aspect_hints = ["//features:experimental"], + deps = ["@abseil-cpp//absl/log:check"], +) + +crubit_rust_test( + name = "nonunpin_experimental_test", + srcs = ["nonunpin_experimental_test.rs"], + cc_deps = [":nonunpin_experimental"], + # LINT.IfChange + rustc_flags = ["-Zallow-features=negative_impls"], + # LINT.ThenChange(//docs/overview/unstable_features.md) + deps = [ + "//support:ctor", + "@crate_index//:googletest", + ], +)
diff --git a/rs_bindings_from_cc/test/struct/nonunpin/nonunpin_experimental_test.rs b/rs_bindings_from_cc/test/struct/nonunpin/nonunpin_experimental_test.rs new file mode 100644 index 0000000..889ec56 --- /dev/null +++ b/rs_bindings_from_cc/test/struct/nonunpin/nonunpin_experimental_test.rs
@@ -0,0 +1,159 @@ +// Part of the Crubit project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +#![feature(negative_impls)] + +use ctor::{ + ctor, emplace, mov, Assign, ConstRvalueReference, Ctor, CtorNew, Emplace, Infallible, + RvalueReference, +}; +use googletest::prelude::*; +use nonunpin_experimental::Nonunpin; +use std::pin::Pin; + +#[gtest] +fn test_move_construct() { + ctor::emplace! { + let mut x = Nonunpin::ctor_new(42); + let mut y = ctor::mov!(x.as_mut()); + } + + assert_eq!(x.value(), 0); // moved-from + assert_eq!(y.value(), 42); // moved-to + + assert_eq!(x.addr(), &*x as *const _ as usize); + assert_eq!(y.addr(), &*y as *const _ as usize); +} + +#[gtest] +fn test_move_assign() { + ctor::emplace! { + let mut x = Nonunpin::ctor_new(42); + let mut y = Nonunpin::ctor_new(8); + } + + y.as_mut().assign(ctor::mov!(x.as_mut())); + + assert_eq!(x.value(), 0); // moved-from + assert_eq!(y.value(), 42); // moved-to + + assert_eq!(x.addr(), &*x as *const _ as usize); + assert_eq!(y.addr(), &*y as *const _ as usize); +} + +#[gtest] +fn test_copy_construct() { + ctor::emplace! { + let x = Nonunpin::ctor_new(42); + let y = ctor::copy(&*x); + } + + assert_eq!(x.value(), 42); + assert_eq!(y.value(), 42); + + assert_eq!(x.addr(), &*x as *const _ as usize); + assert_eq!(y.addr(), &*y as *const _ as usize); +} + +#[gtest] +fn test_copy_assign() { + ctor::emplace! { + let x = Nonunpin::ctor_new(42); + let mut y = Nonunpin::ctor_new(8); + } + y.as_mut().assign(&*x); + + assert_eq!(x.value(), 42); + assert_eq!(y.value(), 42); + + assert_eq!(x.addr(), &*x as *const _ as usize); + assert_eq!(y.addr(), &*y as *const _ as usize); +} + +/// Test that the struct can be returned and passed as all the reference +/// types, and passed by value. +#[gtest] +fn test_ref() { + ctor::emplace! { + let mut x = Nonunpin::ctor_new(42); + } + { + let x_ref: Pin<&mut Nonunpin> = x.as_mut().AsMutRef(); + assert_eq!(nonunpin_experimental::GetValueFromMutRef(x_ref), 42); + assert_eq!(nonunpin_experimental::GetValueFromMutRef(x.as_mut()), 42); + } + { + let x_ref: &Nonunpin = x.AsConstRef(); + assert_eq!(nonunpin_experimental::GetValueFromConstRef(x_ref), 42); + assert_eq!(nonunpin_experimental::GetValueFromConstRef(&x), 42); + } + { + let x_ref: RvalueReference<Nonunpin> = x.as_mut().AsRvalueRef(); + assert_eq!(nonunpin_experimental::GetValueFromRvalueRef(x_ref), 42); + assert_eq!(nonunpin_experimental::GetValueFromRvalueRef(ctor::mov!(x.as_mut())), 42); + } + { + let x_ref: ConstRvalueReference<Nonunpin> = x.AsConstRvalueRef(); + assert_eq!(nonunpin_experimental::GetValueFromConstRvalueRef(x_ref), 42); + assert_eq!(nonunpin_experimental::GetValueFromConstRvalueRef(ctor::const_mov!(&*x)), 42); + assert_eq!( + nonunpin_experimental::GetValueFromConstRvalueRef(ctor::const_mov!(x.as_mut())), + 42 + ); + } + { + assert_eq!(nonunpin_experimental::GetValueFromValue(ctor::copy(&*x)), 42); + assert_eq!(nonunpin_experimental::GetValueFromValue(ctor::mov!(x)), 42); + } +} + +/// An example showing a C++ non-trivially-relocatable class as a field in a +/// Rust struct. There are two ways to do this: +/// +/// 1. storing C++ class indirectly (e.g., in a Box), or, +/// 2. storing by-value. +/// +/// This test specicially demonstrates the second: storing a C++ class by +/// value, even in the worst case of it not being trivially-relocatable. +/// In that case, the struct containing it must *also* become +/// non-trivially-relocatable, and it becomes ~exactly as difficult to deal +/// with as the C++ class it contains. +#[gtest] +fn test_struct_field() { + #[ctor::recursively_pinned] + struct MyStruct { + field_1: u32, + field_2: Nonunpin, + } + + impl MyStruct { + fn new() -> impl Ctor<Output = Self, Error = Infallible> { + ctor!(MyStruct { field_1: 4, field_2: Nonunpin::ctor_new(2) }) + } + } + + emplace! { let mut my_struct = MyStruct::new(); } + assert_eq!(my_struct.field_1, 4); + assert_eq!(my_struct.field_2.value(), 2); + // use projection (from recursively_pinned/pin_project) to mutate the struct: + let mut my_struct = my_struct.project_pin(); + *my_struct.field_1 = 5; + my_struct.field_2.as_mut().assign(mov!(emplace!(Nonunpin::ctor_new(3)))); + assert_eq!(*my_struct.field_1, 5); + assert_eq!(my_struct.field_2.value(), 3); +} + +/// The example from the ctor.rs docs; copy-pasted. +#[gtest] +fn test_swap() { + fn swap(mut x: Pin<&mut Nonunpin>, mut y: Pin<&mut Nonunpin>) { + emplace! { let mut tmp = mov!(x.as_mut()); } + x.assign(mov!(y.as_mut())); + y.assign(mov!(tmp)); + } + let mut c1 = Box::emplace(Nonunpin::ctor_new(1)); + let mut c2 = Box::emplace(Nonunpin::ctor_new(2)); + swap(c1.as_mut(), c2.as_mut()); + assert_eq!(c1.value(), 2); + assert_eq!(c2.value(), 1); +}
diff --git a/rs_bindings_from_cc/test/struct/nonunpin/nonunpin_test.rs b/rs_bindings_from_cc/test/struct/nonunpin/nonunpin_test.rs index 4a408cc..fb1c189 100644 --- a/rs_bindings_from_cc/test/struct/nonunpin/nonunpin_test.rs +++ b/rs_bindings_from_cc/test/struct/nonunpin/nonunpin_test.rs
@@ -3,8 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #![feature(negative_impls)] -use ctor::{ctor, emplace, mov, ConstRvalueReference, Ctor, Emplace, Infallible, RvalueReference}; -use ctor::{Assign as _, CtorNew as _, ReconstructUnchecked as _}; +use ctor::{ctor, emplace, CtorNew, ReconstructUnchecked}; use googletest::prelude::*; use nonunpin::{Nonmovable, Nonunpin, NonunpinStruct, ReturnsNonmovable}; use std::pin::Pin; @@ -30,65 +29,6 @@ } #[gtest] -fn test_move_construct() { - ctor::emplace! { - let mut x = Nonunpin::ctor_new(42); - let mut y = ctor::mov!(x.as_mut()); - } - - assert_eq!(x.value(), 0); // moved-from - assert_eq!(y.value(), 42); // moved-to - - assert_eq!(x.addr(), &*x as *const _ as usize); - assert_eq!(y.addr(), &*y as *const _ as usize); -} - -#[gtest] -fn test_move_assign() { - ctor::emplace! { - let mut x = Nonunpin::ctor_new(42); - let mut y = Nonunpin::ctor_new(8); - } - - y.as_mut().assign(ctor::mov!(x.as_mut())); - - assert_eq!(x.value(), 0); // moved-from - assert_eq!(y.value(), 42); // moved-to - - assert_eq!(x.addr(), &*x as *const _ as usize); - assert_eq!(y.addr(), &*y as *const _ as usize); -} - -#[gtest] -fn test_copy_construct() { - ctor::emplace! { - let x = Nonunpin::ctor_new(42); - let y = ctor::copy(&*x); - } - - assert_eq!(x.value(), 42); - assert_eq!(y.value(), 42); - - assert_eq!(x.addr(), &*x as *const _ as usize); - assert_eq!(y.addr(), &*y as *const _ as usize); -} - -#[gtest] -fn test_copy_assign() { - ctor::emplace! { - let x = Nonunpin::ctor_new(42); - let mut y = Nonunpin::ctor_new(8); - } - y.as_mut().assign(&*x); - - assert_eq!(x.value(), 42); - assert_eq!(y.value(), 42); - - assert_eq!(x.addr(), &*x as *const _ as usize); - assert_eq!(y.addr(), &*y as *const _ as usize); -} - -#[gtest] fn test_methods() { ctor::emplace! { let mut x = Nonunpin::ctor_new(42); @@ -97,40 +37,6 @@ assert_eq!(x.value(), 24); } -/// Test that the struct can be returned and passed as all the reference -/// types, and passed by value. -#[gtest] -fn test_ref() { - ctor::emplace! { - let mut x = Nonunpin::ctor_new(42); - } - { - let x_ref: Pin<&mut Nonunpin> = x.as_mut().AsMutRef(); - assert_eq!(nonunpin::GetValueFromMutRef(x_ref), 42); - assert_eq!(nonunpin::GetValueFromMutRef(x.as_mut()), 42); - } - { - let x_ref: &Nonunpin = x.AsConstRef(); - assert_eq!(nonunpin::GetValueFromConstRef(x_ref), 42); - assert_eq!(nonunpin::GetValueFromConstRef(&x), 42); - } - { - let x_ref: RvalueReference<Nonunpin> = x.as_mut().AsRvalueRef(); - assert_eq!(nonunpin::GetValueFromRvalueRef(x_ref), 42); - assert_eq!(nonunpin::GetValueFromRvalueRef(ctor::mov!(x.as_mut())), 42); - } - { - let x_ref: ConstRvalueReference<Nonunpin> = x.AsConstRvalueRef(); - assert_eq!(nonunpin::GetValueFromConstRvalueRef(x_ref), 42); - assert_eq!(nonunpin::GetValueFromConstRvalueRef(ctor::const_mov!(&*x)), 42); - assert_eq!(nonunpin::GetValueFromConstRvalueRef(ctor::const_mov!(x.as_mut())), 42); - } - { - assert_eq!(nonunpin::GetValueFromValue(ctor::copy(&*x)), 42); - assert_eq!(nonunpin::GetValueFromValue(ctor::mov!(x)), 42); - } -} - #[gtest] fn test_aggregate() { ctor::emplace! { @@ -180,42 +86,6 @@ } /// An example showing a C++ non-trivially-relocatable class as a field in a -/// Rust struct. There are two ways to do this: -/// -/// 1. storing C++ class indirectly (e.g., in a Box), or, -/// 2. storing by-value. -/// -/// This test specicially demonstrates the second: storing a C++ class by -/// value, even in the worst case of it not being trivially-relocatable. -/// In that case, the struct containing it must *also* become -/// non-trivially-relocatable, and it becomes ~exactly as difficult to deal -/// with as the C++ class it contains. -#[gtest] -fn test_struct_field() { - #[ctor::recursively_pinned] - struct MyStruct { - field_1: u32, - field_2: Nonunpin, - } - - impl MyStruct { - fn new() -> impl Ctor<Output = Self, Error = Infallible> { - ctor!(MyStruct { field_1: 4, field_2: Nonunpin::ctor_new(2) }) - } - } - - emplace! { let mut my_struct = MyStruct::new(); } - assert_eq!(my_struct.field_1, 4); - assert_eq!(my_struct.field_2.value(), 2); - // use projection (from recursively_pinned/pin_project) to mutate the struct: - let mut my_struct = my_struct.project_pin(); - *my_struct.field_1 = 5; - my_struct.field_2.as_mut().assign(mov!(emplace!(Nonunpin::ctor_new(3)))); - assert_eq!(*my_struct.field_1, 5); - assert_eq!(my_struct.field_2.value(), 3); -} - -/// An example showing a C++ non-trivially-relocatable class as a field in a /// Rust union. This mirrors the struct case, storing by value. /// /// It is also quite ugly, but, fortunately, these unions are not common. @@ -242,18 +112,3 @@ assert_eq!(my_union.int, 2); } } - -/// The example from the ctor.rs docs; copy-pasted. -#[gtest] -fn test_swap() { - fn swap(mut x: Pin<&mut Nonunpin>, mut y: Pin<&mut Nonunpin>) { - emplace! { let mut tmp = mov!(x.as_mut()); } - x.assign(mov!(y.as_mut())); - y.assign(mov!(tmp)); - } - let mut c1 = Box::emplace(Nonunpin::ctor_new(1)); - let mut c2 = Box::emplace(Nonunpin::ctor_new(2)); - swap(c1.as_mut(), c2.as_mut()); - assert_eq!(c1.value(), 2); - assert_eq!(c2.value(), 1); -}
diff --git a/rs_bindings_from_cc/test/struct/operator_and/operator_and.golden.cc b/rs_bindings_from_cc/test/struct/operator_and/operator_and.golden.cc index ad59b22..924223a 100644 --- a/rs_bindings_from_cc/test/struct/operator_and/operator_and.golden.cc +++ b/rs_bindings_from_cc/test/struct/operator_and/operator_and.golden.cc
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/struct/operator_and:operator_and -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #include "support/internal/cxx20_backports.h" #include "support/internal/offsetof.h"
diff --git a/rs_bindings_from_cc/test/struct/operators/BUILD b/rs_bindings_from_cc/test/struct/operators/BUILD index 01a2962..bc995ed 100644 --- a/rs_bindings_from_cc/test/struct/operators/BUILD +++ b/rs_bindings_from_cc/test/struct/operators/BUILD
@@ -36,7 +36,7 @@ deps = [ "//support:ctor", "@crate_index//:googletest", - "@crate_index//:static_assertions", + "@crate_index//:static_assertions", # v1 ], ) @@ -71,6 +71,6 @@ deps = [ "//support:ctor", "@crate_index//:googletest", - "@crate_index//:static_assertions", + "@crate_index//:static_assertions", # v1 ], )
diff --git a/rs_bindings_from_cc/test/supported_feature_set/BUILD b/rs_bindings_from_cc/test/supported_feature_set/BUILD index d0e3452..6b0b921 100644 --- a/rs_bindings_from_cc/test/supported_feature_set/BUILD +++ b/rs_bindings_from_cc/test/supported_feature_set/BUILD
@@ -15,7 +15,10 @@ crubit_test_cc_library( name = "no_bindings", hdrs = ["no_bindings.h"], - aspect_hints = ["//features:supported"], + aspect_hints = [ + "//features:supported", + "//features:non_unpin_ctor", + ], ) crubit_rust_test( @@ -30,7 +33,7 @@ deps = [ "//support:oops", "@crate_index//:googletest", - "@crate_index//:static_assertions", + "@crate_index//:static_assertions", # v1 ], )
diff --git a/rs_bindings_from_cc/test/supported_feature_set/no_bindings.h b/rs_bindings_from_cc/test/supported_feature_set/no_bindings.h index 3305dfa..919c958 100644 --- a/rs_bindings_from_cc/test/supported_feature_set/no_bindings.h +++ b/rs_bindings_from_cc/test/supported_feature_set/no_bindings.h
@@ -10,11 +10,6 @@ #include <set> namespace crubit::no_bindings { -struct Nontrivial { - ~Nontrivial() {} // NOLINT(modernize-use-equals-default) -}; - -using NontrivialAlias = Nontrivial; using DeprecatedAlias [[deprecated]] = int; // This struct would receive bindings, if it weren't for the unrecognized @@ -38,9 +33,6 @@ using InstantiatedTemplatedStruct = TemplatedStruct<int>; -inline void crubit_accepts_nontrivial_value(Nontrivial) {} -inline Nontrivial crubit_returns_nontrivial_value() { return {}; } - [[clang::vectorcall]] inline void crubit_vectorcall() {} [[noreturn]] inline void crubit_noreturn() {
diff --git a/rs_bindings_from_cc/test/supported_feature_set/no_bindings_test.rs b/rs_bindings_from_cc/test/supported_feature_set/no_bindings_test.rs index c4e5f8c..848a894 100644 --- a/rs_bindings_from_cc/test/supported_feature_set/no_bindings_test.rs +++ b/rs_bindings_from_cc/test/supported_feature_set/no_bindings_test.rs
@@ -11,16 +11,6 @@ assert!(!type_exists!(no_bindings::DeprecatedAlias)); } -#[gtest] -fn test_accepts_nontrivial_value() { - assert!(!value_exists!(no_bindings::crubit_accepts_nontrivial_value)); -} - -#[gtest] -fn test_returns_nontrivial_value() { - assert!(!value_exists!(no_bindings::crubit_returns_nontrivial_value)); -} - // vectorcall attribute is outright ignored on e.g. ARM -- so on that platform, // this isn't actually a different calling convention, and we'd expect bindings // to exist after all.
diff --git a/rs_bindings_from_cc/test/templates/regression_401857961/repro_rs_api.rs b/rs_bindings_from_cc/test/templates/regression_401857961/repro_rs_api.rs index dc7c62f..2e45ce6 100644 --- a/rs_bindings_from_cc/test/templates/regression_401857961/repro_rs_api.rs +++ b/rs_bindings_from_cc/test/templates/regression_401857961/repro_rs_api.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/templates/regression_401857961:repro -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, negative_impls)] @@ -38,18 +38,19 @@ // Generated from: rs_bindings_from_cc/test/templates/regression_401857961/repro.h;l=15 // Error while generating bindings for constructor 'Interval::Interval': + // Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::repro::Interval // Expected first reference parameter `__this` to have a lifetime, found *mut crate::repro::Interval // Generated from: rs_bindings_from_cc/test/templates/regression_401857961/repro.h;l=15 // Error while generating bindings for constructor 'Interval::Interval': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::repro::Interval // Expected first reference parameter `__this` to have a lifetime, found *mut crate::repro::Interval // Generated from: rs_bindings_from_cc/test/templates/regression_401857961/repro.h;l=15 // Error while generating bindings for constructor 'Interval::Interval': - // Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. + // Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::repro::Interval // Expected first reference parameter `__this` to have a lifetime, found *mut crate::repro::Interval
diff --git a/rs_bindings_from_cc/test/templates/regression_401857961/repro_rs_api_impl.cc b/rs_bindings_from_cc/test/templates/regression_401857961/repro_rs_api_impl.cc index 4338c5f..5476106 100644 --- a/rs_bindings_from_cc/test/templates/regression_401857961/repro_rs_api_impl.cc +++ b/rs_bindings_from_cc/test/templates/regression_401857961/repro_rs_api_impl.cc
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/templates/regression_401857961:repro -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, supported #include "support/internal/cxx20_backports.h" #include "support/internal/offsetof.h"
diff --git a/rs_bindings_from_cc/test/types/thread_safety/BUILD b/rs_bindings_from_cc/test/types/thread_safety/BUILD index 53ef33c..09a9d49 100644 --- a/rs_bindings_from_cc/test/types/thread_safety/BUILD +++ b/rs_bindings_from_cc/test/types/thread_safety/BUILD
@@ -22,6 +22,6 @@ ], deps = [ "@crate_index//:googletest", - "@crate_index//:static_assertions", + "@crate_index//:static_assertions", # v1 ], )
diff --git a/rs_bindings_from_cc/test/wrapper/fallback_types/wrapper_library_rs_api.rs b/rs_bindings_from_cc/test/wrapper/fallback_types/wrapper_library_rs_api.rs index 7ce3558..1f6a3f0 100644 --- a/rs_bindings_from_cc/test/wrapper/fallback_types/wrapper_library_rs_api.rs +++ b/rs_bindings_from_cc/test/wrapper/fallback_types/wrapper_library_rs_api.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/wrapper/fallback_types:wrapper_library -// Features: std_unique_ptr, std_vector, supported, wrapper +// Features: do_not_hardcode_status_bridge, non_unpin_ctor, std_unique_ptr, std_vector, supported, wrapper #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes)]
diff --git a/rs_bindings_from_cc/test/wrapper/impl_ctor/impl_ctor_rs_api.rs b/rs_bindings_from_cc/test/wrapper/impl_ctor/impl_ctor_rs_api.rs index 4745bd3..1c1c565 100644 --- a/rs_bindings_from_cc/test/wrapper/impl_ctor/impl_ctor_rs_api.rs +++ b/rs_bindings_from_cc/test/wrapper/impl_ctor/impl_ctor_rs_api.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/wrapper/impl_ctor:impl_ctor -// Features: std_unique_ptr, std_vector, supported, wrapper +// Features: do_not_hardcode_status_bridge, non_unpin_ctor, std_unique_ptr, std_vector, supported, wrapper #![rustfmt::skip] #![feature( @@ -44,6 +44,7 @@ // Generated from: rs_bindings_from_cc/test/wrapper/impl_ctor/impl_ctor.h;l=11 // Error while generating bindings for constructor 'Nontrivial::Nontrivial': +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::Nontrivial // Expected first reference parameter `__this` to have a lifetime, found *mut crate::Nontrivial @@ -61,8 +62,7 @@ /// Generated from: rs_bindings_from_cc/test/wrapper/impl_ctor/impl_ctor.h;l=16 #[inline(always)] -pub(crate) fn Create() -> impl ::ctor::Ctor<Output = crate::Nontrivial, Error = ::ctor::Infallible> -{ +pub fn Create() -> impl ::ctor::Ctor<Output = crate::Nontrivial, Error = ::ctor::Infallible> { unsafe { ::ctor::FnCtor::new(move |dest: *mut crate::Nontrivial| { crate::detail::__rust_thunk___Z6Createv(dest as *mut ::core::ffi::c_void); @@ -72,7 +72,7 @@ /// Generated from: rs_bindings_from_cc/test/wrapper/impl_ctor/impl_ctor.h;l=18 #[inline(always)] -pub(crate) fn Read( +pub fn Read( nontrivial: impl ::ctor::Ctor<Output = crate::Nontrivial, Error = ::ctor::Infallible>, ) -> ::core::ffi::c_int { unsafe {
diff --git a/rs_bindings_from_cc/test/wrapper/pub_crate_types/pub_crate_types_rs_api.rs b/rs_bindings_from_cc/test/wrapper/pub_crate_types/pub_crate_types_rs_api.rs index ea4f2fd..95ad67f 100644 --- a/rs_bindings_from_cc/test/wrapper/pub_crate_types/pub_crate_types_rs_api.rs +++ b/rs_bindings_from_cc/test/wrapper/pub_crate_types/pub_crate_types_rs_api.rs
@@ -4,7 +4,7 @@ // Automatically @generated Rust bindings for the following C++ target: // //rs_bindings_from_cc/test/wrapper/pub_crate_types:pub_crate_types -// Features: std_unique_ptr, std_vector, supported, wrapper +// Features: do_not_hardcode_status_bridge, non_unpin_ctor, std_unique_ptr, std_vector, supported, wrapper #![rustfmt::skip] #![feature(allocator_api, cfg_sanitize, custom_inner_attributes, negative_impls)] @@ -42,18 +42,19 @@ // Generated from: rs_bindings_from_cc/test/wrapper/pub_crate_types/pub_crate_types.h;l=23 // Error while generating bindings for constructor 'CompoundDataType::CompoundDataType': +// Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::CompoundDataType // Expected first reference parameter `__this` to have a lifetime, found *mut crate::CompoundDataType // Generated from: rs_bindings_from_cc/test/wrapper/pub_crate_types/pub_crate_types.h;l=23 // Error while generating bindings for constructor 'CompoundDataType::CompoundDataType': -// Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::CompoundDataType // Expected first reference parameter `__this` to have a lifetime, found *mut crate::CompoundDataType // Generated from: rs_bindings_from_cc/test/wrapper/pub_crate_types/pub_crate_types.h;l=23 // Error while generating bindings for constructor 'CompoundDataType::CompoundDataType': -// Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::CompoundDataType // Expected first reference parameter `__this` to have a lifetime, found *mut crate::CompoundDataType @@ -140,18 +141,19 @@ // Generated from: rs_bindings_from_cc/test/wrapper/pub_crate_types/other_pub_crate_types.h;l=11 // Error while generating bindings for constructor 'Template2<int>::Template2<int>': +// Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::__CcTemplateInst9Template2IiE // Expected first reference parameter `__this` to have a lifetime, found *mut crate::__CcTemplateInst9Template2IiE // Generated from: rs_bindings_from_cc/test/wrapper/pub_crate_types/other_pub_crate_types.h;l=11 // Error while generating bindings for constructor 'Template2<int>::Template2<int>': -// Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::__CcTemplateInst9Template2IiE // Expected first reference parameter `__this` to have a lifetime, found *mut crate::__CcTemplateInst9Template2IiE // Generated from: rs_bindings_from_cc/test/wrapper/pub_crate_types/other_pub_crate_types.h;l=11 // Error while generating bindings for constructor 'Template2<int>::Template2<int>': -// Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::__CcTemplateInst9Template2IiE // Expected first reference parameter `__this` to have a lifetime, found *mut crate::__CcTemplateInst9Template2IiE @@ -179,18 +181,19 @@ // Generated from: rs_bindings_from_cc/test/wrapper/pub_crate_types/pub_crate_types.h;l=11 // Error while generating bindings for constructor 'Template<int>::Template<int>': +// Default constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::__CcTemplateInst8TemplateIiE // Expected first reference parameter `__this` to have a lifetime, found *mut crate::__CcTemplateInst8TemplateIiE // Generated from: rs_bindings_from_cc/test/wrapper/pub_crate_types/pub_crate_types.h;l=11 // Error while generating bindings for constructor 'Template<int>::Template<int>': -// Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::__CcTemplateInst8TemplateIiE // Expected first reference parameter `__this` to have a lifetime, found *mut crate::__CcTemplateInst8TemplateIiE // Generated from: rs_bindings_from_cc/test/wrapper/pub_crate_types/pub_crate_types.h;l=11 // Error while generating bindings for constructor 'Template<int>::Template<int>': -// Unsafe constructors (e.g. with no elided or explicit lifetimes) are intentionally not supported. See b/216648347. +// Move and copy constructors do yet receive bindings. See b/452726517. // Expected first constructor parameter to be a mutable reference, got: *mut crate::__CcTemplateInst8TemplateIiE // Expected first reference parameter `__this` to have a lifetime, found *mut crate::__CcTemplateInst8TemplateIiE
diff --git a/support/BUILD b/support/BUILD index c0eca73..4961167 100644 --- a/support/BUILD +++ b/support/BUILD
@@ -17,6 +17,7 @@ rust_library( name = "ctor", srcs = ["ctor.rs"], + compatible_with = ["//buildenv/target:non_prod"], crate_features = ["unstable"], proc_macro_deps = [":ctor_proc_macros"], # LINT.IfChange @@ -33,14 +34,15 @@ compatible_with = ["//buildenv/target:non_prod"], deps = [ "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:syn", # v1 ], ) cc_library( name = "annotations", hdrs = ["annotations.h"], + compatible_with = ["//buildenv/target:non_prod"], visibility = [ "//visibility:public", ], @@ -52,6 +54,7 @@ cc_library( name = "annotations_internal", hdrs = ["annotations_internal.h"], + compatible_with = ["//buildenv/target:non_prod"], visibility = [ "//visibility:public", ], @@ -69,8 +72,8 @@ ], deps = [ "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:syn", # v1 ], ) @@ -124,6 +127,7 @@ rust_library( name = "forward_declare", srcs = ["forward_declare.rs"], + compatible_with = ["//buildenv/target:non_prod"], crate_features = ["unstable"], proc_macro_deps = [":forward_declare_proc_macros"], # LINT.IfChange @@ -144,8 +148,8 @@ ], deps = [ "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:syn", # v1 ], ) @@ -169,6 +173,7 @@ rust_library( name = "oops", srcs = ["oops.rs"], + compatible_with = ["//buildenv/target:non_prod"], # LINT.IfChange rustc_flags = ["-Zallow-features=negative_impls"], # LINT.ThenChange(//docs/overview/unstable_features.md) @@ -191,6 +196,7 @@ rust_library( name = "bridge_rust", srcs = ["bridge.rs"], + compatible_with = ["//buildenv/target:non_prod"], visibility = [ "//visibility:public", ], @@ -207,6 +213,7 @@ cc_library( name = "bridge_cpp", hdrs = ["bridge.h"], + compatible_with = ["//buildenv/target:non_prod"], visibility = [ "//visibility:public", ], @@ -217,34 +224,7 @@ srcs = ["bridge_test.cc"], deps = [ ":bridge_cpp", - "@googletest//:gtest_main", - ], -) - -cc_library( - name = "status_bridge_cpp", - srcs = ["status_bridge.cc"], - hdrs = ["status_bridge.h"], - visibility = [ - "//visibility:public", - ], - deps = [ - ":bridge_cpp", - "@abseil-cpp//absl/status", - "@abseil-cpp//absl/status:statusor", - "@abseil-cpp//absl/strings:string_view", - ], -) - -cc_test( - name = "status_bridge_cpp_test", - srcs = ["status_bridge_test.cc"], - deps = [ - ":bridge_cpp", - ":status_bridge_cpp", - "@abseil-cpp//absl/status", - "@abseil-cpp//absl/status:statusor", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/support/bridge.h b/support/bridge.h index 0b75f55..5b2fc1a 100644 --- a/support/bridge.h +++ b/support/bridge.h
@@ -5,6 +5,10 @@ #ifndef THIRD_PARTY_CRUBIT_SUPPORT_BRIDGE_H_ #define THIRD_PARTY_CRUBIT_SUPPORT_BRIDGE_H_ +// Allow others to check #ifdef CRUBIT_BRIDGE_ENABLED +#if !defined(SWIG) && defined(__clang__) && __cplusplus >= 202002L +#define CRUBIT_BRIDGE_ENABLED + #include <concepts> #include <cstddef> #include <cstring> @@ -376,4 +380,5 @@ } // namespace crubit +#endif // CRUBIT_BRIDGE_ENABLED #endif // THIRD_PARTY_CRUBIT_SUPPORT_BRIDGE_H_
diff --git a/support/cc_import/BUILD b/support/cc_import/BUILD index fd3ee0f..579ca56 100644 --- a/support/cc_import/BUILD +++ b/support/cc_import/BUILD
@@ -19,7 +19,7 @@ deps = [ ":cc_import_internal", "@crate_index//:proc-macro2", - "@crate_index//:syn", + "@crate_index//:syn", # v1 ], ) @@ -28,12 +28,13 @@ srcs = [ "cc_import_internal.rs", ], + compatible_with = ["//buildenv/target:non_prod"], deps = [ ":merged_namespaces", "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:serde_json", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:serde_json", # v1 + "@crate_index//:syn", # v1 "@rules_rust//util/import:import_internal", ], ) @@ -41,12 +42,13 @@ rust_library( name = "merged_namespaces", srcs = ["merged_namespaces.rs"], + compatible_with = ["//buildenv/target:non_prod"], deps = [ "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:serde", - "@crate_index//:serde_json", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:serde", # v1 + "@crate_index//:serde_json", # v1 + "@crate_index//:syn", # v1 "@rules_rust//util/import:import_internal", ], )
diff --git a/support/cc_std_impl/test/cpp_std_string/BUILD b/support/cc_std_impl/test/cpp_std_string/BUILD index f1d0a0a..ebd4e57 100644 --- a/support/cc_std_impl/test/cpp_std_string/BUILD +++ b/support/cc_std_impl/test/cpp_std_string/BUILD
@@ -18,6 +18,6 @@ ], deps = [ "@crate_index//:googletest", - "@crate_index//:rstest", + "@crate_index//:rstest", # v0_16 ], )
diff --git a/support/cc_std_impl/test/string_view/BUILD b/support/cc_std_impl/test/string_view/BUILD index 1c38f90..2e1f276 100644 --- a/support/cc_std_impl/test/string_view/BUILD +++ b/support/cc_std_impl/test/string_view/BUILD
@@ -49,6 +49,6 @@ srcs = ["test.cc"], deps = [ ":string_view_rs_apis_cc", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/support/cc_std_impl/test/vector/BUILD b/support/cc_std_impl/test/vector/BUILD index f7fbf33..0f376b3 100644 --- a/support/cc_std_impl/test/vector/BUILD +++ b/support/cc_std_impl/test/vector/BUILD
@@ -24,6 +24,6 @@ ], deps = [ "@crate_index//:googletest", - "@crate_index//:static_assertions", + "@crate_index//:static_assertions", # v1 ], )
diff --git a/support/cc_template/BUILD b/support/cc_template/BUILD index 4c37364..323959a 100644 --- a/support/cc_template/BUILD +++ b/support/cc_template/BUILD
@@ -16,19 +16,20 @@ ], deps = [ ":cc_template_impl", - "@crate_index//:syn", + "@crate_index//:syn", # v1 ], ) rust_library( name = "cc_template_impl", srcs = ["cc_template_impl.rs"], + compatible_with = ["//buildenv/target:non_prod"], deps = [ - "@crate_index//:anyhow", + "@crate_index//:anyhow", # v1 "@crate_index//:proc-macro2", - "@crate_index//:quote", - "@crate_index//:serde_json", - "@crate_index//:syn", + "@crate_index//:quote", # v1 + "@crate_index//:serde_json", # v1 + "@crate_index//:syn", # v1 ], ) @@ -42,6 +43,6 @@ crate = ":cc_template_impl", deps = [ "@crate_index//:googletest", - "@crate_index//:maplit", + "@crate_index//:maplit", # v1 ], )
diff --git a/support/ffi_11/BUILD b/support/ffi_11/BUILD index 68e5147..dc37f34 100644 --- a/support/ffi_11/BUILD +++ b/support/ffi_11/BUILD
@@ -5,6 +5,7 @@ rust_library( name = "ffi_11", srcs = glob(["src/*.rs"]), + compatible_with = ["//buildenv/target:non_prod"], crate_features = ["crubit"], visibility = [ "//:__subpackages__",
diff --git a/support/ffi_11/tests/BUILD b/support/ffi_11/tests/BUILD index 2709492..8f8fc9c 100644 --- a/support/ffi_11/tests/BUILD +++ b/support/ffi_11/tests/BUILD
@@ -7,6 +7,6 @@ srcs = ["conversion_test.rs"], deps = [ "//support/ffi_11", - "@crate_index//:static_assertions", + "@crate_index//:static_assertions", # v1 ], )
diff --git a/support/ffi_11/tests/type_identity/rust_api_cc_api.h b/support/ffi_11/tests/type_identity/rust_api_cc_api.h index c8b6b8a..a47bf81 100644 --- a/support/ffi_11/tests/type_identity/rust_api_cc_api.h +++ b/support/ffi_11/tests/type_identity/rust_api_cc_api.h
@@ -4,7 +4,8 @@ // Automatically @generated C++ bindings for the following Rust crate: // rust_api_golden -// Features: std_unique_ptr, std_vector, supported +// Features: do_not_hardcode_status_bridge, std_unique_ptr, std_vector, +// supported // clang-format off #ifndef THIRD_PARTY_CRUBIT_SUPPORT_FFI_11_TESTS_TYPE_IDENTITY_RUST_API_GOLDEN
diff --git a/support/internal/BUILD b/support/internal/BUILD index 7be2ba1..15a9472 100644 --- a/support/internal/BUILD +++ b/support/internal/BUILD
@@ -15,6 +15,7 @@ "sizeof.h", "slot.h", ], + compatible_with = ["//buildenv/target:non_prod"], visibility = [ "//visibility:public", ], @@ -35,7 +36,7 @@ srcs = ["check_no_mutable_aliasing_test.cc"], deps = [ ":bindings_support", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -44,7 +45,7 @@ srcs = ["memswap_test.cc"], deps = [ ":bindings_support", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -53,7 +54,7 @@ srcs = ["offsetof_test.cc"], deps = [ ":bindings_support", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], ) @@ -62,9 +63,9 @@ srcs = ["slot_test.cc"], deps = [ ":bindings_support", + "//testing/base/public:gunit_main", "@abseil-cpp//absl/base:core_headers", "@abseil-cpp//absl/log:check", - "@googletest//:gtest_main", ], ) @@ -73,6 +74,6 @@ srcs = ["sizeof_test.cc"], deps = [ ":bindings_support", - "@googletest//:gtest_main", + "//testing/base/public:gunit_main", ], )
diff --git a/support/internal/slot.h b/support/internal/slot.h index 2707564..4374ed6 100644 --- a/support/internal/slot.h +++ b/support/internal/slot.h
@@ -7,6 +7,8 @@ #ifndef CRUBIT_SUPPORT_INTERNAL_RETURN_VALUE_SLOT_H_ #define CRUBIT_SUPPORT_INTERNAL_RETURN_VALUE_SLOT_H_ +#include <array> +#include <cstddef> #include <memory> #include <utility> @@ -130,6 +132,49 @@ template <typename T> Slot(T) -> Slot<T>; +template <typename T, std::size_t N, std::size_t... I> +constexpr std::array<T, N> unsafe_move_array(T* ptr, + std::index_sequence<I...>) { + return {{T(UnsafeRelocateTag{}, std::move(ptr[I]))...}}; +} + +// TODO: b/451981992 - This works for single-level arrays, but we'd like to +// support arbitrary composite types that include arrays in Slot. +template <typename UT, unsigned S> +class Slot<std::array<UT, S>> { + public: + using T = std::array<UT, S>; + Slot() {} + explicit constexpr Slot(T&& x) { + if constexpr (requires(UT x) { UT(UnsafeRelocateTag{}, std::move(x)); }) { + memcpy(value_.data(), x.data(), sizeof(UT) * S); + } else { + value_ = std::move(x); + } + } + T* Get() { return &value_; } + T AssumeInitAndTakeValue() && { + if constexpr (requires(UT x) { UT(UnsafeRelocateTag{}, std::move(x)); }) { + return unsafe_move_array<UT, S>(value_.data(), + std::make_index_sequence<S>()); + } else { + T return_value(std::move(value_)); + std::destroy_at(&value_); + return return_value; + } + } + Slot(Slot&& other) { value_ = std::move(other.value_); } + ~Slot() {} + + Slot(const Slot&) = delete; + Slot& operator=(const Slot&) = delete; + Slot& operator=(Slot&&) = delete; + + private: + union { + T value_; + }; +}; } // namespace crubit #endif // CRUBIT_SUPPORT_INTERNAL_RETURN_VALUE_SLOT_H_
diff --git a/support/rs_std/BUILD b/support/rs_std/BUILD index a9e4a4d..2964c94 100644 --- a/support/rs_std/BUILD +++ b/support/rs_std/BUILD
@@ -19,6 +19,7 @@ hdrs = ["char.h"], # Enable bidirectional bindings (via crubit_internal_rust_type). aspect_hints = ["//features:experimental"], + compatible_with = ["//buildenv/target:non_prod"], visibility = ["//visibility:public"], # It is important to be thoughtful when adding new dependencies for `char` @@ -76,6 +77,7 @@ cc_deps = [ ":cpp_waker", ], + compatible_with = ["//buildenv/target:non_prod"], visibility = ["//visibility:public"], ) @@ -91,6 +93,7 @@ hdrs = ["slice_ref.h"], # Enable bidirectional bindings (via crubit_internal_rust_type). aspect_hints = ["//features:experimental"], + compatible_with = ["//buildenv/target:non_prod"], visibility = [ "//visibility:public", ], @@ -124,6 +127,7 @@ hdrs = ["str_ref.h"], # Enable bidirectional bindings (via crubit_internal_rust_type). aspect_hints = ["//features:experimental"], + compatible_with = ["//buildenv/target:non_prod"], visibility = [ "//visibility:public", ],
diff --git a/support/rs_std/internal/BUILD b/support/rs_std/internal/BUILD index 719cfcc..cd15860 100644 --- a/support/rs_std/internal/BUILD +++ b/support/rs_std/internal/BUILD
@@ -7,6 +7,7 @@ cc_library( name = "is_utf8", hdrs = ["is_utf8.h"], + compatible_with = ["//buildenv/target:non_prod"], visibility = [ "//visibility:public", ],
diff --git a/support/stable_fallback/BUILD b/support/stable_fallback/BUILD index ade2dd5..d86f592 100644 --- a/support/stable_fallback/BUILD +++ b/support/stable_fallback/BUILD
@@ -8,6 +8,7 @@ name = "forward_declare", testonly = True, srcs = ["//support:forward_declare.rs"], + compatible_with = ["//buildenv/target:non_prod"], crate_features = [], proc_macro_deps = ["//support:forward_declare_proc_macros"], # LINT.IfChange
diff --git a/support/status_bridge.cc b/support/status_bridge.cc deleted file mode 100644 index 50c2983..0000000 --- a/support/status_bridge.cc +++ /dev/null
@@ -1,166 +0,0 @@ -// Part of the Crubit project, under the Apache License v2.0 with LLVM -// Exceptions. See /LICENSE for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "support/status_bridge.h" - -#include "support/bridge.h" - -#include <cstddef> -#include <cstdint> -#include <string> -#include <utility> - -#include "absl/status/status.h" -#include "absl/strings/string_view.h" - -namespace crubit { - -constexpr uintptr_t kRustOkStatusRep = 0; - -static_assert( - sizeof(absl::Status) == sizeof(uintptr_t) && - alignof(absl::Status) == alignof(uintptr_t), - "Crubit invariant broken, please reach out to us at <internal link>"); - -void StatusAbi::Encode(absl::Status value, Encoder& encoder) { - if (value.ok()) { - // No reference counting, okay to just drop. - encoder.EncodeTransmute<uintptr_t>(kRustOkStatusRep); - return; - } - - // Ownership of the Status is transferred into the buffer. - alignas(absl::Status) char rep[sizeof(absl::Status)]; - new (rep) absl::Status(std::move(value)); - encoder.EncodeTransmute<uintptr_t>(*reinterpret_cast<uintptr_t*>(rep)); -} - -absl::Status StatusAbi::Decode(Decoder& decoder) { - uintptr_t rep = decoder.DecodeTransmute<uintptr_t>(); - if (rep == kRustOkStatusRep) { - return absl::OkStatus(); - } - - return absl::Status(reinterpret_cast<absl::Status&&>(rep)); -} - -// These functions do not have prototypes because they are extern "C" functions -// that are linked to Rust code, and never called from C++ code. -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-prototypes" - -// Increments the reference count of the `Status` with the provided `rep`. -// -// The caller must ensure that: -// * `rep` is a valid `rep_` from a `Status`, -// * if `rep` is the allocated variant, the underlying `StatusRep*` has not -// been deleted. -// -// The caller may assume that the reference count has been incremented. -extern "C" void absl_status_internal_ref(uintptr_t rep) { - alignas(absl::Status) char erase[sizeof(absl::Status)]; - new (erase) absl::Status(reinterpret_cast<const absl::Status&>(rep)); -} - -// Takes semantic overship over the `rep` by creating a `Status` from it, and -// then immediately destroys it to decrement the reference count. -// -// The caller must ensure that: -// * `rep` is a valid `rep_` from a `Status`, -// * if `rep` is the allocated variant, the underlying `StatusRep*` has not -// been deleted prior to calling this function. -extern "C" void absl_status_internal_unref(uintptr_t rep) { - (void)absl::Status(reinterpret_cast<absl::Status&&>(rep)); -} - -// A C-compatible representation of a `string_view` used to pass string views by -// value across the C ABI. -struct c_string_view { - size_t size; - const char* data; -}; - -// Creates a rep for a new `Status` with the provided code and message. -// -// The caller must ensure that `message` constitutes valid `absl::string_view`. -// -// The caller may assume that the returned rep is a valid `rep_` from a C++ -// `Status` meaning it is never 0, and that if it is the allocated variant, the -// reference count is set to 1 which accounts for the ownership that the caller -// is expected to take. -extern "C" uintptr_t absl_status_internal_new(int code, c_string_view message) { - alignas(absl::Status) char rep[sizeof(absl::Status)]; - new (rep) absl::Status(static_cast<absl::StatusCode>(code), - absl::string_view(message.data, message.size)); - return *reinterpret_cast<uintptr_t*>(rep); -} - -// Returns the raw code of the `Status`. -// -// The caller must ensure that: -// * `rep` is a valid `rep_` from a `Status`, -// * if `rep` is the allocated variant, the underlying `StatusRep*` has not -// been deleted. -// -// The caller may not assume that the returned value is a valid `StatusCode` -// value. -extern "C" int absl_status_internal_raw_code(uintptr_t rep) { - return reinterpret_cast<const absl::Status&>(rep).raw_code(); -} - -// Returns the message of the `Status`. -// -// The caller must ensure that: -// * `rep` is a valid `rep_` from a `Status`, -// * if `rep` is the allocated variant, the underlying `StatusRep*` has not -// been deleted, -// -// The caller may assume that the returned `string_view` is valid until `rep` -// is converted back to a `Status` and the `Status` is destroyed. -extern "C" c_string_view absl_status_internal_message(uintptr_t rep) { - auto message = reinterpret_cast<const absl::Status&>(rep).message(); - return {message.size(), message.data()}; -} - -// Returns true if two Status values are equal, false otherwise. -// -// The caller must ensure that for `rep` in (lhs, rhs): -// * `rep` is a valid `rep_` from a `Status`, -// * if `rep` is the allocated variant, the underlying `StatusRep*` has not -// been deleted, -extern "C" bool absl_status_internal_operator_equals(uintptr_t lhs, - uintptr_t rhs) { - return reinterpret_cast<const absl::Status&>(lhs) == - reinterpret_cast<const absl::Status&>(rhs); -} - -// Writes the stringified representation to a Rust `fmt::Formatter`. -// -// The caller must ensure that: -// * `rep` is a valid `rep_` from a `Status`, -// * if `rep` is the allocated variant, the underlying `StatusRep*` has not -// been deleted, -// * `formatter` can be safely casted to a `&mut fmt::Formatter`, -// * `cb` is a function that takes the underlying type of `formatter` and -// returns true if the string was successfully written. -// -// The caller may assume that if `cb` is called, then the void* is the -// `formatter` passed into this function, and that the c_string_view is valid -// for the duration of `cb`. -extern "C" bool absl_status_internal_to_string(uintptr_t rep, void* formatter, - bool (*cb)(void*, - c_string_view)) { - std::string s = reinterpret_cast<absl::Status&>(rep).ToString(); - if (s.empty()) { - return true; - } - - // Need to use a function pointer so that :status can compile without linking - // against :additional_status_src. - return cb(formatter, {s.size(), s.data()}); -} - -#pragma clang diagnostic pop - -} // namespace crubit
diff --git a/support/status_bridge.h b/support/status_bridge.h deleted file mode 100644 index faea975..0000000 --- a/support/status_bridge.h +++ /dev/null
@@ -1,49 +0,0 @@ -// Part of the Crubit project, under the Apache License v2.0 with LLVM -// Exceptions. See /LICENSE for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#ifndef THIRD_PARTY_CRUBIT_SUPPORT_STATUS_BRIDGE_H_ -#define THIRD_PARTY_CRUBIT_SUPPORT_STATUS_BRIDGE_H_ - -#include "support/bridge.h" - -#include <cstddef> -#include <cstdint> - -#include "absl/status/status.h" -#include "absl/status/statusor.h" - -namespace crubit { - -struct StatusAbi { - using Value = absl::Status; - static constexpr size_t kSize = sizeof(uintptr_t); - static void Encode(Value value, Encoder& encoder); - static Value Decode(Decoder& decoder); -}; - -template <typename Abi> -struct StatusOrAbi { - static_assert(is_crubit_abi<Abi>, - "StatusOrAbi requires Abi to be is_crubit_abi"); - using Value = absl::StatusOr<typename Abi::Value>; - static constexpr size_t kSize = StatusAbi::kSize + Abi::kSize; - static void Encode(Value value, Encoder& encoder) { - encoder.Encode<StatusAbi>(value.status()); - if (value.ok()) { - encoder.Encode<Abi>(*std::move(value)); - } - } - static Value Decode(Decoder& decoder) { - absl::Status status(decoder.Decode<StatusAbi>()); - if (status.ok()) { - return decoder.Decode<Abi>(); - } else { - return status; - } - } -}; - -} // namespace crubit - -#endif // THIRD_PARTY_CRUBIT_SUPPORT_BRIDGE_REMOTE_STATUS_BRIDGE_H_
diff --git a/support/status_bridge_test.cc b/support/status_bridge_test.cc deleted file mode 100644 index 9e8ad55..0000000 --- a/support/status_bridge_test.cc +++ /dev/null
@@ -1,60 +0,0 @@ -// Part of the Crubit project, under the Apache License v2.0 with LLVM -// Exceptions. See /LICENSE for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include "support/status_bridge.h" - -#include "crubit/support/bridge.h" -#include "gtest/gtest.h" -#include "absl/status/status.h" -#include "absl/status/statusor.h" - -namespace crubit::bridge { -namespace { - -TEST(BridgeTest, RoundtripOkStatus) { - using Abi = StatusAbi; - - absl::Status original = absl::OkStatus(); - - unsigned char buf[Abi::kSize]; - internal::Encode<Abi>(buf, original); - absl::Status value = internal::Decode<Abi>(buf); - EXPECT_EQ(value, original); -} - -TEST(BridgeTest, RoundtripErrStatus) { - using Abi = StatusAbi; - - absl::Status original = absl::InternalError("test"); - - unsigned char buf[Abi::kSize]; - internal::Encode<Abi>(buf, original); - absl::Status value = internal::Decode<Abi>(buf); - EXPECT_EQ(value, original); -} - -TEST(BridgeTest, RoundtripOkStatusOr) { - using Abi = StatusOrAbi<TransmuteAbi<int>>; - - absl::StatusOr<int> original = 123; - - unsigned char buf[Abi::kSize]; - internal::Encode<Abi>(buf, original); - absl::StatusOr<int> value = internal::Decode<Abi>(buf); - EXPECT_EQ(value, original); -} - -TEST(BridgeTest, RoundtripErrStatusOr) { - using Abi = StatusOrAbi<TransmuteAbi<int>>; - - absl::StatusOr<int> original = absl::InternalError("test"); - - unsigned char buf[Abi::kSize]; - internal::Encode<Abi>(buf, original); - absl::StatusOr<int> value = internal::Decode<Abi>(buf); - EXPECT_EQ(value, original); -} - -} // namespace -} // namespace crubit::bridge