diff --git a/BUCK b/BUCK index 728c4e1a3..dbd4235fc 100644 --- a/BUCK +++ b/BUCK @@ -47,6 +47,7 @@ rust_binary( "//third-party:proc-macro2", "//third-party:quote", "//third-party:syn", + "//third-party:unicode-ident", ], ) @@ -76,6 +77,7 @@ rust_library( "//third-party:quote", "//third-party:rustversion", "//third-party:syn", + "//third-party:unicode-ident", ], ) @@ -101,6 +103,7 @@ rust_library( "//third-party:quote", "//third-party:scratch", "//third-party:syn", + "//third-party:unicode-ident", ], ) @@ -125,5 +128,6 @@ rust_library( "//third-party:proc-macro2", "//third-party:quote", "//third-party:syn", + "//third-party:unicode-ident", ], ) diff --git a/BUILD.bazel b/BUILD.bazel index 4cce24dc6..0f1998d56 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -39,6 +39,7 @@ rust_binary( "@crates.io//:proc-macro2", "@crates.io//:quote", "@crates.io//:syn", + "@crates.io//:unicode-ident", ], ) @@ -70,6 +71,7 @@ rust_proc_macro( "@crates.io//:proc-macro2", "@crates.io//:quote", "@crates.io//:syn", + "@crates.io//:unicode-ident", ], ) @@ -87,6 +89,7 @@ rust_library( "@crates.io//:quote", "@crates.io//:scratch", "@crates.io//:syn", + "@crates.io//:unicode-ident", ], ) @@ -104,5 +107,6 @@ rust_library( "@crates.io//:proc-macro2", "@crates.io//:quote", "@crates.io//:syn", + "@crates.io//:unicode-ident", ], ) diff --git a/gen/build/Cargo.toml b/gen/build/Cargo.toml index 4737ab97f..f79bb1aca 100644 --- a/gen/build/Cargo.toml +++ b/gen/build/Cargo.toml @@ -24,6 +24,7 @@ proc-macro2 = { version = "1.0.74", default-features = false, features = ["span- quote = { version = "1.0.35", default-features = false } scratch = "1.0.5" syn = { version = "2.0.46", default-features = false, features = ["clone-impls", "full", "parsing", "printing"] } +unicode-ident = "1.0.22" [dev-dependencies] cxx = { version = "1.0", path = "../.." } diff --git a/gen/cmd/Cargo.toml b/gen/cmd/Cargo.toml index 1a295ad2b..a07d587e3 100644 --- a/gen/cmd/Cargo.toml +++ b/gen/cmd/Cargo.toml @@ -23,6 +23,7 @@ indexmap = "2.9.0" proc-macro2 = { version = "1.0.74", default-features = false, features = ["span-locations"] } quote = { version = "1.0.35", default-features = false } syn = { version = "2.0.46", default-features = false, features = ["clone-impls", "full", "parsing", "printing"] } +unicode-ident = "1.0.22" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/gen/lib/Cargo.toml b/gen/lib/Cargo.toml index 1eae18a5d..4783aaf11 100644 --- a/gen/lib/Cargo.toml +++ b/gen/lib/Cargo.toml @@ -18,6 +18,7 @@ indexmap = "2.9.0" proc-macro2 = { version = "1.0.74", default-features = false, features = ["span-locations"] } quote = { version = "1.0.35", default-features = false } syn = { version = "2.0.46", default-features = false, features = ["clone-impls", "full", "parsing", "printing"] } +unicode-ident = "1.0.22" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/macro/Cargo.toml b/macro/Cargo.toml index 7f492b6df..90d641960 100644 --- a/macro/Cargo.toml +++ b/macro/Cargo.toml @@ -20,6 +20,7 @@ indexmap = "2.9.0" proc-macro2 = "1.0.74" quote = "1.0.35" syn = { version = "2.0.46", features = ["full"] } +unicode-ident = "1.0.22" [dev-dependencies] cxx = { version = "1.0", path = ".." } diff --git a/syntax/check.rs b/syntax/check.rs index 3654cd1ad..d83e3c33d 100644 --- a/syntax/check.rs +++ b/syntax/check.rs @@ -1,15 +1,21 @@ use crate::syntax::atom::Atom::{self, *}; use crate::syntax::message::Message; +use crate::syntax::names::ForeignName; use crate::syntax::report::Errors; use crate::syntax::visit::{self, Visit}; use crate::syntax::{ error, ident, trivial, Api, Array, Enum, ExternFn, ExternType, FnKind, Impl, Lang, Lifetimes, - NamedType, Ptr, Receiver, Ref, Signature, SliceRef, Struct, Trait, Ty1, Type, TypeAlias, Types, + NamedType, Pair, Ptr, Receiver, Ref, Signature, SliceRef, Struct, Trait, Ty1, Type, TypeAlias, + Types, }; -use proc_macro2::{Delimiter, Group, Ident, TokenStream}; +use proc_macro2::{Delimiter, Group, TokenStream}; use quote::{quote, ToTokens}; +use std::collections::HashSet; use std::fmt::Display; -use syn::{GenericParam, Generics, Lifetime}; +use std::sync::LazyLock; +use syn::ext::IdentExt; +use syn::parse::Parser; +use syn::{GenericParam, Generics, Ident, Lifetime}; pub(crate) struct Check<'a> { apis: &'a [Api], @@ -331,7 +337,7 @@ fn check_type_fn(cx: &mut Check, ty: &Signature) { fn check_api_struct(cx: &mut Check, strct: &Struct) { let name = &strct.name; - check_reserved_name(cx, &name.rust); + check_type_name(cx, name); check_lifetimes(cx, &strct.generics); if strct.fields.is_empty() { @@ -374,6 +380,7 @@ fn check_api_struct(cx: &mut Check, strct: &Struct) { } for field in &strct.fields { + check_name(cx, &field.name); if let Type::Fn(_) = field.ty { cx.error( field, @@ -388,7 +395,7 @@ fn check_api_struct(cx: &mut Check, strct: &Struct) { } fn check_api_enum(cx: &mut Check, enm: &Enum) { - check_reserved_name(cx, &enm.name.rust); + check_type_name(cx, &enm.name); check_lifetimes(cx, &enm.generics); if enm.variants.is_empty() && !enm.explicit_repr { @@ -399,6 +406,10 @@ fn check_api_enum(cx: &mut Check, enm: &Enum) { ); } + for variant in &enm.variants { + check_name(cx, &variant.name); + } + for derive in &enm.derives { match derive.what { Trait::BitAnd @@ -434,7 +445,7 @@ fn check_api_enum(cx: &mut Check, enm: &Enum) { } fn check_api_type(cx: &mut Check, ety: &ExternType) { - check_reserved_name(cx, &ety.name.rust); + check_type_name(cx, &ety.name); check_lifetimes(cx, &ety.generics); for derive in &ety.derives { @@ -468,6 +479,7 @@ fn check_api_type(cx: &mut Check, ety: &ExternType) { } fn check_api_fn(cx: &mut Check, efn: &ExternFn) { + check_fn_name(cx, &efn.name); match efn.lang { Lang::Cxx | Lang::CxxUnwind => { if !efn.generics.params.is_empty() && !efn.trusted { @@ -582,6 +594,7 @@ fn check_api_fn(cx: &mut Check, efn: &ExternFn) { } fn check_api_type_alias(cx: &mut Check, alias: &TypeAlias) { + check_type_name(cx, &alias.name); check_lifetimes(cx, &alias.generics); for derive in &alias.derives { @@ -682,7 +695,62 @@ fn check_mut_return_restriction(cx: &mut Check, efn: &ExternFn) { ); } -fn check_reserved_name(cx: &mut Check, ident: &Ident) { +/// Checks an API `name` (e.g. name of a type, function, method, etc.). +fn check_name(cx: &mut Check, name: &Pair) { + let cxx_name = name.cxx.as_str(); + let mut report_error = move |msg: String| { + let mut tokens = name.rust.clone(); + tokens.set_span(name.cxx.span()); + cx.error(tokens, msg); + }; + + #[rustfmt::skip] + static CPP_RESERVED_KEYWORDS: LazyLock> = LazyLock::new(|| { + // Taken from https://en.cppreference.com/w/cpp/keywords.html + [ + "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel", "atomic_commit", + "atomic_noexcept", "auto", "bitand", "bitor", "bool", "break", "case", "catch", + "char", "char8_t", "char16_t", "char32_t", "class", "compl", "concept", "const", + "consteval", "constexpr", "constinit", "const_cast", "continue", "contract_assert", + "co_await", "co_return", "co_yield", "", "decltype", "default", "delete", "do", + "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", + "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", + "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", + "or_eq", "private", "protected", "public", "", "reflexpr", "register", + "reinterpret_cast", "requires", "return", "short", "signed", "sizeof", "static", + "static_assert", "static_cast", "struct", "switch", "synchronized", "template", + "this", "thread_local", "throw", "true", "try", "typedef", "typeid", "typename", + "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", + "xor", "xor_eq", + ].into_iter().collect() + }); + if CPP_RESERVED_KEYWORDS.contains(cxx_name) { + let msg = format!("C++ reserved keyword can't be used as a C++ identifier: {cxx_name}"); + report_error(msg); + } + + // Most API names need to have a form of a valid C++ identifier. API names + // that allow other forms (e.g. `operator==` for function names) should + // check and allow those forms first (e.g. by `check_fn_name`), before + // deciding to call `check_name`. + if let Err(e) = Ident::parse_any.parse_str(cxx_name) { + let msg = format!("Invalid C++ identifier: {e}"); + report_error(msg); + } +} + +/// Checks `name` of a function or a method. +fn check_fn_name(cx: &mut Check, name: &Pair) { + if ForeignName::is_valid_operator_name(name.cxx.as_str()) { + return; + } + + check_name(cx, name); +} + +/// Checks `name` of a type (e.g. a struct, enum, or a type alias). +fn check_type_name(cx: &mut Check, name: &Pair) { + let ident = &name.rust; if ident == "Box" || ident == "UniquePtr" || ident == "SharedPtr" @@ -694,6 +762,8 @@ fn check_reserved_name(cx: &mut Check, ident: &Ident) { { cx.error(ident, "reserved name"); } + + check_name(cx, name); } fn check_reserved_lifetime(cx: &mut Check, lifetime: &Lifetime) { diff --git a/syntax/names.rs b/syntax/names.rs index 7afa5a9e3..949eefeb8 100644 --- a/syntax/names.rs +++ b/syntax/names.rs @@ -1,8 +1,10 @@ use crate::syntax::symbol::Segment; use crate::syntax::{Lifetimes, NamedType, Pair, Symbol}; use proc_macro2::{Ident, Span}; +use std::collections::HashSet; use std::fmt::{self, Display}; use std::iter; +use std::sync::LazyLock; use syn::ext::IdentExt; use syn::parse::{Error, Parser, Result}; use syn::punctuated::Punctuated; @@ -10,6 +12,7 @@ use syn::punctuated::Punctuated; #[derive(Clone)] pub(crate) struct ForeignName { text: String, + span: Span, } impl Pair { @@ -36,16 +39,49 @@ impl NamedType { impl ForeignName { pub(crate) fn parse(text: &str, span: Span) -> Result { - // TODO: support C++ names containing whitespace (`unsigned int`) or - // non-alphanumeric characters (`operator++`). + if ForeignName::is_valid_operator_name(text) { + return Ok(ForeignName { + text: text.to_string(), + span, + }); + } + match Ident::parse_any.parse_str(text) { Ok(ident) => { let text = ident.to_string(); - Ok(ForeignName { text }) + Ok(ForeignName { text, span }) } Err(err) => Err(Error::new(span, err)), } } + + pub(crate) fn as_str(&self) -> &str { + &self.text + } + + pub(crate) fn span(&self) -> Span { + self.span + } + + pub(crate) fn is_valid_operator_name(name: &str) -> bool { + #[rustfmt::skip] + static CPP_OPERATORS: LazyLock> = LazyLock::new(|| { + // Based on `llvm/llvm-project/clang/include/clang/Basic/OperatorKinds.def`. + // Excluding `?` because it is not overridable. + // + // TODO: Consider also allowing `operator ` + // (see https://en.cppreference.com/w/cpp/language/cast_operator.html). + [ + " new", " delete", " new[]", " delete[]", " co_await", + "+", "-", "*", "/", "%", "^", "&", "|", "~", "!", "=", "<", ">", + "+=", "-=", "*=", "/=", "%=", "^=", "&=", "|=", + "<<", ">>", "<<=", ">>=", "==", "!=", "<=", ">=", "<=>", + "&&", "||", "++", "--", ",", "->*", "->", "()", "[]", + ].into_iter().collect() + }); + name.strip_prefix("operator") + .is_some_and(|suffix| CPP_OPERATORS.contains(suffix)) + } } impl Display for ForeignName { diff --git a/syntax/symbol.rs b/syntax/symbol.rs index 24f87506d..b79c02998 100644 --- a/syntax/symbol.rs +++ b/syntax/symbol.rs @@ -91,9 +91,34 @@ impl Segment for Pair { impl Segment for ForeignName { fn write(&self, symbol: &mut Symbol) { - // TODO: support C++ names containing whitespace (`unsigned int`) or - // non-alphanumeric characters (`operator++`). - self.to_string().write(symbol); + /// Escapes arbitrary C++ name (e.g. `operator==`) into a String + /// that is a valid C identifier. It is important that this is an + /// [injective function](https://en.wikipedia.org/wiki/Injective_function) + /// (i.e. distinct `name`s need to map to distinct results). + fn escape(name: &str) -> String { + let mut result = String::with_capacity(name.len()); + for (index, ch) in name.chars().enumerate() { + if ch == '_' { + write!(&mut result, "_u").unwrap(); + continue; + } + + let should_escape = if index == 0 { + !unicode_ident::is_xid_start(ch) + } else { + !unicode_ident::is_xid_continue(ch) + }; + if should_escape { + write!(&mut result, "_{:x}h", ch as u32).unwrap(); + continue; + } + + write!(&mut result, "{ch}").unwrap(); + } + result + } + + escape(self.as_str()).write(symbol); } } @@ -114,3 +139,33 @@ pub(crate) fn join(segments: &[&dyn Segment]) -> Symbol { assert!(!symbol.0.is_empty()); symbol } + +#[cfg(test)] +mod test { + use super::join; + use crate::syntax::ForeignName; + use proc_macro2::Span; + + #[test] + fn test_impl_segment_for_foreign_name() { + fn t(foreign_name_str: &str, expected_symbol_str: &str) { + let foreign_name = ForeignName::parse(foreign_name_str, Span::call_site()).unwrap(); + let symbol = join(&[&foreign_name]); + let actual_symbol_str = symbol.to_string(); + assert_eq!( + actual_symbol_str, expected_symbol_str, + "Expecting `{foreign_name_str}` to mangle as `{expected_symbol_str}` \ + but got `{actual_symbol_str}` instead.", + ); + } + + t("foo", "foo"); + + // Escaping of non-identifier characters like `=`. + t("operator==", "operator_3dh_3dh"); + + // Feeble attempt of testing injectivity + // (need to escape `_` to avoid a conflict with result of the previous test). + t("operator_3dh_3dh", "operator_u3dh_u3dh"); + } +} diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs index 2cb3022c8..f24692245 100644 --- a/tests/ffi/lib.rs +++ b/tests/ffi/lib.rs @@ -234,6 +234,9 @@ pub mod ffi { #[rust_name = "str_overloaded_function"] fn cOverloadedFunction(x: &str) -> String; + #[cxx_name = "operator=="] + fn cpp_eq_operator(&self, other_n: usize) -> bool; + #[namespace = "other"] fn ns_c_take_ns_shared(shared: AShared); @@ -352,6 +355,9 @@ pub mod ffi { #[cxx_name = "rAliasedFunction"] fn r_aliased_function(x: i32) -> String; + #[cxx_name = "operator=="] + fn r_operator_eq_for_usize_operand(self: &R, rhs: usize) -> bool; + #[Self = "Shared"] fn r_static_method_on_shared() -> usize; @@ -473,6 +479,10 @@ impl R { fn r_static_method() -> usize { 2024 } + + fn r_operator_eq_for_usize_operand(&self, rhs: usize) -> bool { + self.0 == rhs + } } pub struct Reference<'a>(pub &'a String); diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc index 22d67b340..b00dc9446 100644 --- a/tests/ffi/tests.cc +++ b/tests/ffi/tests.cc @@ -844,6 +844,7 @@ extern "C" const char *cxx_run_test() noexcept { ASSERT(r->get() == 2020); ASSERT(r->set(2021) == 2021); ASSERT(r->get() == 2021); + ASSERT(*r == 2021); using std::swap; auto r2 = r_return_box(); diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h index ab6a868bd..67b7e7b1e 100644 --- a/tests/ffi/tests.h +++ b/tests/ffi/tests.h @@ -73,6 +73,10 @@ class C { // in an `impl ffi::C` block. size_t &r_method_on_c_get_mut() noexcept; + bool operator==(size_t other_n) const { + return n == other_n; + } + private: size_t n; std::vector v; diff --git a/tests/test.rs b/tests/test.rs index 7eb300706..1f7a3f499 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -391,7 +391,7 @@ unsafe extern "C" fn cxx_test_suite_r_is_correct(r: *const R) -> bool { } #[test] -fn test_rust_name_attribute() { +fn test_cxx_name_attribute() { assert_eq!("2020", ffi::i32_overloaded_function(2020)); assert_eq!("2020", ffi::str_overloaded_function("2020")); let unique_ptr = ffi::c_return_unique_ptr(); @@ -399,6 +399,14 @@ fn test_rust_name_attribute() { assert_eq!("2020", unique_ptr.str_overloaded_method("2020")); } +#[test] +fn test_rust_name_attribute() { + let mut c = ffi::c_return_unique_ptr(); + c.pin_mut().set(123); + assert!(c.cpp_eq_operator(123)); + assert!(!c.cpp_eq_operator(456)); +} + #[test] fn test_extern_trivial() { let mut d = ffi2::c_return_trivial(); diff --git a/tests/ui/invalid_cxx_type_name.rs b/tests/ui/invalid_cxx_type_name.rs new file mode 100644 index 000000000..a51119484 --- /dev/null +++ b/tests/ui/invalid_cxx_type_name.rs @@ -0,0 +1,31 @@ +#[cxx::bridge] +mod ffi { + #[cxx_name = "operator=="] + struct S { + #[cxx_name = "operator<"] + field: usize, + } + + #[cxx_name = "operator>"] + enum E { + Variant1, + #[cxx_name = "operator!"] + Variant2, + Variant3, + } + + unsafe extern "C++" { + #[cxx_name = "operator+"] + type C2; + + #[cxx_name = "operator*"] + type Alias = some_other_crate::SomeOtherType; + } + + extern "Rust" { + #[cxx_name = "operator/"] + type R2; + } +} + +fn main() {} diff --git a/tests/ui/invalid_cxx_type_name.stderr b/tests/ui/invalid_cxx_type_name.stderr new file mode 100644 index 000000000..d2e5c9a2b --- /dev/null +++ b/tests/ui/invalid_cxx_type_name.stderr @@ -0,0 +1,41 @@ +error: Invalid C++ identifier: unexpected token + --> tests/ui/invalid_cxx_type_name.rs:3:18 + | +3 | #[cxx_name = "operator=="] + | ^^^^^^^^^^^^ + +error: Invalid C++ identifier: unexpected token + --> tests/ui/invalid_cxx_type_name.rs:5:22 + | +5 | #[cxx_name = "operator<"] + | ^^^^^^^^^^^ + +error: Invalid C++ identifier: unexpected token + --> tests/ui/invalid_cxx_type_name.rs:9:18 + | +9 | #[cxx_name = "operator>"] + | ^^^^^^^^^^^ + +error: Invalid C++ identifier: unexpected token + --> tests/ui/invalid_cxx_type_name.rs:12:22 + | +12 | #[cxx_name = "operator!"] + | ^^^^^^^^^^^ + +error: Invalid C++ identifier: unexpected token + --> tests/ui/invalid_cxx_type_name.rs:18:22 + | +18 | #[cxx_name = "operator+"] + | ^^^^^^^^^^^ + +error: Invalid C++ identifier: unexpected token + --> tests/ui/invalid_cxx_type_name.rs:21:22 + | +21 | #[cxx_name = "operator*"] + | ^^^^^^^^^^^ + +error: Invalid C++ identifier: unexpected token + --> tests/ui/invalid_cxx_type_name.rs:26:22 + | +26 | #[cxx_name = "operator/"] + | ^^^^^^^^^^^ diff --git a/tests/ui/reserved_cxx_name.rs b/tests/ui/reserved_cxx_name.rs new file mode 100644 index 000000000..4733f4119 --- /dev/null +++ b/tests/ui/reserved_cxx_name.rs @@ -0,0 +1,42 @@ +#[cxx::bridge] +mod ffi { + #[cxx_name = "constinit"] + struct S { + consteval: usize, + + #[cxx_name = "constexpr"] + field2: usize, + } + + #[cxx_name = "bitand"] + enum E { + Variant1, + bitor, + Variant3, + } + + unsafe extern "C++" { + fn const_cast(); + + type C; + fn reinterpret_cast(self: &C); + + #[cxx_name = "static_cast"] + type C2; + + #[cxx_name = "dynamic_cast"] + type Alias = some_other_crate::SomeOtherType; + } + + extern "Rust" { + fn private(); + + type R; + fn protected(self: &R); + + #[cxx_name = "public"] + type R2; + } +} + +fn main() {} diff --git a/tests/ui/reserved_cxx_name.stderr b/tests/ui/reserved_cxx_name.stderr new file mode 100644 index 000000000..9877d64b2 --- /dev/null +++ b/tests/ui/reserved_cxx_name.stderr @@ -0,0 +1,71 @@ +error: C++ reserved keyword can't be used as a C++ identifier: constinit + --> tests/ui/reserved_cxx_name.rs:3:18 + | +3 | #[cxx_name = "constinit"] + | ^^^^^^^^^^^ + +error: C++ reserved keyword can't be used as a C++ identifier: consteval + --> tests/ui/reserved_cxx_name.rs:5:9 + | +5 | consteval: usize, + | ^^^^^^^^^ + +error: C++ reserved keyword can't be used as a C++ identifier: constexpr + --> tests/ui/reserved_cxx_name.rs:7:22 + | +7 | #[cxx_name = "constexpr"] + | ^^^^^^^^^^^ + +error: C++ reserved keyword can't be used as a C++ identifier: bitand + --> tests/ui/reserved_cxx_name.rs:11:18 + | +11 | #[cxx_name = "bitand"] + | ^^^^^^^^ + +error: C++ reserved keyword can't be used as a C++ identifier: bitor + --> tests/ui/reserved_cxx_name.rs:14:9 + | +14 | bitor, + | ^^^^^ + +error: C++ reserved keyword can't be used as a C++ identifier: const_cast + --> tests/ui/reserved_cxx_name.rs:19:12 + | +19 | fn const_cast(); + | ^^^^^^^^^^ + +error: C++ reserved keyword can't be used as a C++ identifier: reinterpret_cast + --> tests/ui/reserved_cxx_name.rs:22:12 + | +22 | fn reinterpret_cast(self: &C); + | ^^^^^^^^^^^^^^^^ + +error: C++ reserved keyword can't be used as a C++ identifier: static_cast + --> tests/ui/reserved_cxx_name.rs:24:22 + | +24 | #[cxx_name = "static_cast"] + | ^^^^^^^^^^^^^ + +error: C++ reserved keyword can't be used as a C++ identifier: dynamic_cast + --> tests/ui/reserved_cxx_name.rs:27:22 + | +27 | #[cxx_name = "dynamic_cast"] + | ^^^^^^^^^^^^^^ + +error: C++ reserved keyword can't be used as a C++ identifier: private + --> tests/ui/reserved_cxx_name.rs:32:12 + | +32 | fn private(); + | ^^^^^^^ + +error: C++ reserved keyword can't be used as a C++ identifier: protected + --> tests/ui/reserved_cxx_name.rs:35:12 + | +35 | fn protected(self: &R); + | ^^^^^^^^^ + +error: C++ reserved keyword can't be used as a C++ identifier: public + --> tests/ui/reserved_cxx_name.rs:37:22 + | +37 | #[cxx_name = "public"] + | ^^^^^^^^ diff --git a/third-party/BUCK b/third-party/BUCK index 4246fd34b..e5e0af2b4 100644 --- a/third-party/BUCK +++ b/third-party/BUCK @@ -706,6 +706,12 @@ cargo.rust_library( visibility = [], ) +alias( + name = "unicode-ident", + actual = ":unicode-ident-1.0.22", + visibility = ["PUBLIC"], +) + http_archive( name = "unicode-ident-1.0.22.crate", sha256 = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5", diff --git a/third-party/Cargo.lock b/third-party/Cargo.lock index baf33fa3c..e0deecb20 100644 --- a/third-party/Cargo.lock +++ b/third-party/Cargo.lock @@ -189,6 +189,7 @@ dependencies = [ "scratch", "serde", "syn", + "unicode-ident", ] [[package]] diff --git a/third-party/Cargo.toml b/third-party/Cargo.toml index 538d3c77c..a1b700e7b 100644 --- a/third-party/Cargo.toml +++ b/third-party/Cargo.toml @@ -18,3 +18,4 @@ rustversion = "1" scratch = "1" serde = { version = "1", features = ["derive"] } syn = { version = "2.0.1", features = ["full"] } +unicode-ident = "1.0.22" diff --git a/third-party/bazel/BUILD.bazel b/third-party/bazel/BUILD.bazel index 85cbb951f..9a9ca55c3 100644 --- a/third-party/bazel/BUILD.bazel +++ b/third-party/bazel/BUILD.bazel @@ -162,3 +162,15 @@ alias( actual = "@vendor__syn-2.0.111//:syn", tags = ["manual"], ) + +alias( + name = "unicode-ident-1.0.22", + actual = "@vendor__unicode-ident-1.0.22//:unicode_ident", + tags = ["manual"], +) + +alias( + name = "unicode-ident", + actual = "@vendor__unicode-ident-1.0.22//:unicode_ident", + tags = ["manual"], +) diff --git a/third-party/bazel/defs.bzl b/third-party/bazel/defs.bzl index 8b1089a24..a2afb3924 100644 --- a/third-party/bazel/defs.bzl +++ b/third-party/bazel/defs.bzl @@ -305,6 +305,7 @@ _NORMAL_DEPENDENCIES = { "scratch": Label("@vendor//:scratch-1.0.9"), "serde": Label("@vendor//:serde-1.0.228"), "syn": Label("@vendor//:syn-2.0.111"), + "unicode-ident": Label("@vendor//:unicode-ident-1.0.22"), }, }, } @@ -694,4 +695,5 @@ def crate_repositories(): struct(repo = "vendor__scratch-1.0.9", is_dev_dep = False), struct(repo = "vendor__serde-1.0.228", is_dev_dep = False), struct(repo = "vendor__syn-2.0.111", is_dev_dep = False), + struct(repo = "vendor__unicode-ident-1.0.22", is_dev_dep = False), ]