Skip to content

Commit debd9d5

Browse files
authored
Merge pull request #337 from dtolnay/impl
Improve error message on a conflicting explicit impl
2 parents 1cbd1b2 + 0531f43 commit debd9d5

File tree

5 files changed

+87
-23
lines changed

5 files changed

+87
-23
lines changed

macro/src/expand.rs

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ use crate::syntax::namespace::Namespace;
44
use crate::syntax::report::Errors;
55
use crate::syntax::symbol::Symbol;
66
use crate::syntax::{
7-
self, check, mangle, Api, Enum, ExternFn, ExternType, Signature, Struct, Type, TypeAlias, Types,
7+
self, check, mangle, Api, Enum, ExternFn, ExternType, Impl, Signature, Struct, Type, TypeAlias,
8+
Types,
89
};
9-
use proc_macro2::{Ident, TokenStream};
10+
use proc_macro2::{Ident, Span, TokenStream};
1011
use quote::{format_ident, quote, quote_spanned, ToTokens};
1112
use std::mem;
1213
use syn::{parse_quote, Result, Token};
@@ -62,6 +63,7 @@ fn expand(ffi: Module, apis: &[Api], types: &Types) -> TokenStream {
6263
}
6364

6465
for ty in types {
66+
let explicit_impl = types.explicit_impls.get(ty);
6567
if let Type::RustBox(ty) = ty {
6668
if let Type::Ident(ident) = &ty.inner {
6769
if Atom::from(ident).is_none() {
@@ -77,20 +79,20 @@ fn expand(ffi: Module, apis: &[Api], types: &Types) -> TokenStream {
7779
} else if let Type::UniquePtr(ptr) = ty {
7880
if let Type::Ident(ident) = &ptr.inner {
7981
if Atom::from(ident).is_none()
80-
&& (!types.aliases.contains_key(ident) || types.explicit_impls.contains(ty))
82+
&& (explicit_impl.is_some() || !types.aliases.contains_key(ident))
8183
{
82-
expanded.extend(expand_unique_ptr(namespace, ident, types));
84+
expanded.extend(expand_unique_ptr(namespace, ident, types, explicit_impl));
8385
}
8486
}
8587
} else if let Type::CxxVector(ptr) = ty {
8688
if let Type::Ident(ident) = &ptr.inner {
8789
if Atom::from(ident).is_none()
88-
&& (!types.aliases.contains_key(ident) || types.explicit_impls.contains(ty))
90+
&& (explicit_impl.is_some() || !types.aliases.contains_key(ident))
8991
{
9092
// Generate impl for CxxVector<T> if T is a struct or opaque
9193
// C++ type. Impl for primitives is already provided by cxx
9294
// crate.
93-
expanded.extend(expand_cxx_vector(namespace, ident));
95+
expanded.extend(expand_cxx_vector(namespace, ident, explicit_impl));
9496
}
9597
}
9698
}
@@ -784,7 +786,12 @@ fn expand_rust_vec(namespace: &Namespace, elem: &Ident) -> TokenStream {
784786
}
785787
}
786788

787-
fn expand_unique_ptr(namespace: &Namespace, ident: &Ident, types: &Types) -> TokenStream {
789+
fn expand_unique_ptr(
790+
namespace: &Namespace,
791+
ident: &Ident,
792+
types: &Types,
793+
explicit_impl: Option<&Impl>,
794+
) -> TokenStream {
788795
let name = ident.to_string();
789796
let prefix = format!("cxxbridge04$unique_ptr${}{}$", namespace, ident);
790797
let link_null = format!("{}null", prefix);
@@ -810,8 +817,13 @@ fn expand_unique_ptr(namespace: &Namespace, ident: &Ident, types: &Types) -> Tok
810817
None
811818
};
812819

813-
quote! {
814-
unsafe impl ::cxx::private::UniquePtrTarget for #ident {
820+
let begin_span =
821+
explicit_impl.map_or_else(Span::call_site, |explicit| explicit.impl_token.span);
822+
let end_span = explicit_impl.map_or_else(Span::call_site, |explicit| explicit.brace_token.span);
823+
let unsafe_token = format_ident!("unsafe", span = begin_span);
824+
825+
quote_spanned! {end_span=>
826+
#unsafe_token impl ::cxx::private::UniquePtrTarget for #ident {
815827
const __NAME: &'static dyn ::std::fmt::Display = &#name;
816828
fn __null() -> *mut ::std::ffi::c_void {
817829
extern "C" {
@@ -857,7 +869,12 @@ fn expand_unique_ptr(namespace: &Namespace, ident: &Ident, types: &Types) -> Tok
857869
}
858870
}
859871

860-
fn expand_cxx_vector(namespace: &Namespace, elem: &Ident) -> TokenStream {
872+
fn expand_cxx_vector(
873+
namespace: &Namespace,
874+
elem: &Ident,
875+
explicit_impl: Option<&Impl>,
876+
) -> TokenStream {
877+
let _ = explicit_impl;
861878
let name = elem.to_string();
862879
let prefix = format!("cxxbridge04$std$vector${}{}$", namespace, elem);
863880
let link_size = format!("{}size", prefix);
@@ -869,8 +886,13 @@ fn expand_cxx_vector(namespace: &Namespace, elem: &Ident) -> TokenStream {
869886
let link_unique_ptr_release = format!("{}release", unique_ptr_prefix);
870887
let link_unique_ptr_drop = format!("{}drop", unique_ptr_prefix);
871888

872-
quote! {
873-
unsafe impl ::cxx::private::VectorElement for #elem {
889+
let begin_span =
890+
explicit_impl.map_or_else(Span::call_site, |explicit| explicit.impl_token.span);
891+
let end_span = explicit_impl.map_or_else(Span::call_site, |explicit| explicit.brace_token.span);
892+
let unsafe_token = format_ident!("unsafe", span = begin_span);
893+
894+
quote_spanned! {end_span=>
895+
#unsafe_token impl ::cxx::private::VectorElement for #elem {
874896
const __NAME: &'static dyn ::std::fmt::Display = &#name;
875897
fn __vector_size(v: &::cxx::CxxVector<Self>) -> usize {
876898
extern "C" {

syntax/impls.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use crate::syntax::{ExternFn, Receiver, Ref, Signature, Slice, Ty1, Type};
1+
use crate::syntax::{ExternFn, Impl, Receiver, Ref, Signature, Slice, Ty1, Type};
2+
use std::borrow::Borrow;
23
use std::hash::{Hash, Hasher};
34
use std::mem;
45
use std::ops::{Deref, DerefMut};
@@ -238,3 +239,38 @@ impl Hash for Receiver {
238239
ty.hash(state);
239240
}
240241
}
242+
243+
impl Hash for Impl {
244+
fn hash<H: Hasher>(&self, state: &mut H) {
245+
let Impl {
246+
impl_token: _,
247+
ty,
248+
brace_token: _,
249+
} = self;
250+
ty.hash(state);
251+
}
252+
}
253+
254+
impl Eq for Impl {}
255+
256+
impl PartialEq for Impl {
257+
fn eq(&self, other: &Impl) -> bool {
258+
let Impl {
259+
impl_token: _,
260+
ty,
261+
brace_token: _,
262+
} = self;
263+
let Impl {
264+
impl_token: _,
265+
ty: ty2,
266+
brace_token: _,
267+
} = other;
268+
ty == ty2
269+
}
270+
}
271+
272+
impl Borrow<Type> for &Impl {
273+
fn borrow(&self) -> &Type {
274+
&self.ty
275+
}
276+
}

syntax/set.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ where
3535
{
3636
self.set.contains(value)
3737
}
38+
39+
pub fn get<Q>(&self, value: &Q) -> Option<&'a T>
40+
where
41+
&'a T: Borrow<Q>,
42+
Q: ?Sized + Hash + Eq,
43+
{
44+
self.set.get(value).copied()
45+
}
3846
}
3947

4048
impl<'s, 'a, T> IntoIterator for &'s OrderedSet<&'a T> {

syntax/types.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::syntax::atom::Atom::{self, *};
22
use crate::syntax::report::Errors;
33
use crate::syntax::set::OrderedSet as Set;
4-
use crate::syntax::{Api, Derive, Enum, ExternFn, ExternType, Struct, Type, TypeAlias};
4+
use crate::syntax::{Api, Derive, Enum, ExternFn, ExternType, Impl, Struct, Type, TypeAlias};
55
use proc_macro2::Ident;
66
use quote::ToTokens;
77
use std::collections::{BTreeMap as Map, HashSet as UnorderedSet};
@@ -15,7 +15,7 @@ pub struct Types<'a> {
1515
pub aliases: Map<&'a Ident, &'a TypeAlias>,
1616
pub untrusted: Map<&'a Ident, &'a ExternType>,
1717
pub required_trivial: Map<&'a Ident, TrivialReason<'a>>,
18-
pub explicit_impls: Set<&'a Type>,
18+
pub explicit_impls: Set<&'a Impl>,
1919
}
2020

2121
impl<'a> Types<'a> {
@@ -137,7 +137,7 @@ impl<'a> Types<'a> {
137137
}
138138
Api::Impl(imp) => {
139139
visit(&mut all, &imp.ty);
140-
explicit_impls.insert(&imp.ty);
140+
explicit_impls.insert(imp);
141141
}
142142
}
143143
}

tests/ui/unique_ptr_twice.stderr

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
error[E0119]: conflicting implementations of trait `cxx::private::UniquePtrTarget` for type `here::C`:
2-
--> $DIR/unique_ptr_twice.rs:10:1
2+
--> $DIR/unique_ptr_twice.rs:16:5
33
|
4-
1 | #[cxx::bridge]
5-
| -------------- first implementation here
4+
7 | impl UniquePtr<C> {}
5+
| ----------------- first implementation here
66
...
7-
10 | #[cxx::bridge]
8-
| ^^^^^^^^^^^^^^ conflicting implementation for `here::C`
9-
|
10-
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
7+
16 | impl UniquePtr<C> {}
8+
| ^^^^^^^^^^^^^^^^^ conflicting implementation for `here::C`

0 commit comments

Comments
 (0)