Skip to content

Commit 6762422

Browse files
authored
windows-clang constant repr (#4962)
1 parent db973ad commit 6762422

4 files changed

Lines changed: 104 additions & 14 deletions

File tree

crates/libs/clang/src/lib.rs

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -738,19 +738,17 @@ impl Snapshot {
738738
return Err(Error(format!("duplicate planned name `{}`", function.name)));
739739
}
740740
}
741-
for constant in plan.constants {
741+
for planned in plan.constants {
742+
let constant = planned.constant;
742743
let encoding = match &constant.value {
743744
Value::Utf8(_) => " #[encoding(\"ansi\")]\n",
744745
Value::Utf16(_) => " #[encoding(\"utf-16\")]\n",
745746
_ => "",
746747
};
747-
let ty = match &constant.value {
748-
Value::Utf8(_) | Value::Utf16(_) => "String".to_string(),
749-
_ => constant_type_name(&constant.ty, &plan.type_names),
750-
};
751748
let item = format!(
752-
"{encoding} const {}: {ty} = {};\n",
749+
"{encoding} const {}: {} = {};\n",
753750
rdl_ident(&constant.name),
751+
planned.ty,
754752
value_name(&constant.value)
755753
);
756754
if items
@@ -1617,10 +1615,52 @@ impl Snapshot {
16171615
)));
16181616
}
16191617
}
1618+
let mut pointer_aliases: BTreeMap<&str, Vec<&str>> = BTreeMap::new();
1619+
for fact in &self.facts {
1620+
let FactData::Typedef {
1621+
target: TypeRef::Named { name: target, .. } | TypeRef::Generic { name: target, .. },
1622+
} = &fact.data
1623+
else {
1624+
continue;
1625+
};
1626+
pointer_aliases.entry(target).or_default().push(&fact.name);
1627+
}
1628+
let mut pointer_alias_queue: Vec<_> = pointer_interface_aliases.keys().cloned().collect();
1629+
while let Some(target) = pointer_alias_queue.pop() {
1630+
let projected = pointer_interface_aliases[&target].clone();
1631+
for alias in pointer_aliases.get(target.as_str()).into_iter().flatten() {
1632+
if let Some(previous) = pointer_interface_aliases.get(*alias) {
1633+
if previous != &projected {
1634+
return Err(Error(format!(
1635+
"interface pointer alias `{alias}` has conflicting targets"
1636+
)));
1637+
}
1638+
} else {
1639+
pointer_interface_aliases.insert((*alias).to_string(), projected.clone());
1640+
pointer_alias_queue.push((*alias).to_string());
1641+
}
1642+
}
1643+
}
16201644
for (alias, target) in &pointer_interface_aliases {
16211645
type_names.insert(alias.clone(), target.clone());
16221646
}
16231647
types.retain(|planned| !pointer_interface_aliases.contains_key(&planned.fact.name));
1648+
let mut constants: Vec<_> = constants
1649+
.into_iter()
1650+
.filter_map(|constant| {
1651+
let ty = match &constant.value {
1652+
Value::Utf8(_) | Value::Utf16(_) => Some("String".to_string()),
1653+
_ => constant_type_name(
1654+
&constant.ty,
1655+
&type_names,
1656+
&interface_names,
1657+
&pointer_interface_aliases,
1658+
&constant.root.tu,
1659+
),
1660+
}?;
1661+
Some(PlannedConstant { constant, ty })
1662+
})
1663+
.collect();
16241664
if timing {
16251665
eprintln!(
16261666
"clang plan interfaces: {:.2}s",
@@ -1651,9 +1691,12 @@ impl Snapshot {
16511691
return Err(Error(format!("duplicate planned name `{}`", planned.name)));
16521692
}
16531693
}
1654-
for constant in &constants {
1655-
if !value_output_names.insert(constant.name.as_str()) {
1656-
return Err(Error(format!("duplicate planned name `{}`", constant.name)));
1694+
for planned in &constants {
1695+
if !value_output_names.insert(planned.constant.name.as_str()) {
1696+
return Err(Error(format!(
1697+
"duplicate planned name `{}`",
1698+
planned.constant.name
1699+
)));
16571700
}
16581701
}
16591702
for function in &functions {
@@ -1663,7 +1706,7 @@ impl Snapshot {
16631706
return Err(Error(format!("duplicate planned name `{}`", function.name)));
16641707
}
16651708
}
1666-
constants.sort_by(|left, right| left.name.cmp(&right.name));
1709+
constants.sort_by(|left, right| left.constant.name.cmp(&right.constant.name));
16671710
functions.sort_by(|left, right| left.name.cmp(&right.name));
16681711
if timing {
16691712
eprintln!(
@@ -1722,6 +1765,11 @@ struct PlannedFact<'a> {
17221765
name: String,
17231766
}
17241767

1768+
struct PlannedConstant<'a> {
1769+
constant: &'a Constant,
1770+
ty: String,
1771+
}
1772+
17251773
#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
17261774
enum OutputKind {
17271775
Value,
@@ -1732,7 +1780,7 @@ struct Plan<'a> {
17321780
types: Vec<PlannedFact<'a>>,
17331781
values: Vec<PlannedFact<'a>>,
17341782
functions: Vec<&'a Fact>,
1735-
constants: Vec<&'a Constant>,
1783+
constants: Vec<PlannedConstant<'a>>,
17361784
type_names: BTreeMap<String, String>,
17371785
interface_names: BTreeSet<(String, String)>,
17381786
interface_guids: BTreeMap<String, String>,
@@ -3806,16 +3854,36 @@ fn pointer_run(mut ty: &TypeRef) -> (bool, usize, &TypeRef) {
38063854
(mutable, depth, ty)
38073855
}
38083856

3809-
fn constant_type_name(ty: &TypeRef, type_names: &BTreeMap<String, String>) -> String {
3810-
match ty {
3857+
fn constant_type_name(
3858+
ty: &TypeRef,
3859+
type_names: &BTreeMap<String, String>,
3860+
interface_names: &BTreeSet<(String, String)>,
3861+
pointer_interface_aliases: &BTreeMap<String, String>,
3862+
tu: &str,
3863+
) -> Option<String> {
3864+
let name = match ty {
38113865
TypeRef::Scalar(Scalar::Bool) => "u32".to_string(),
3866+
TypeRef::Named { name, .. } if pointer_interface_aliases.contains_key(name) => {
3867+
return None;
3868+
}
3869+
TypeRef::Named { name, .. } | TypeRef::Generic { name, .. }
3870+
if interface_names.contains(&(tu.to_string(), name.clone())) =>
3871+
{
3872+
return None;
3873+
}
38123874
TypeRef::Named { name, .. } if type_names.contains_key(name) => {
38133875
planned_type_name(ty, type_names)
38143876
}
38153877
TypeRef::Named { name, .. } => canonical_named_type(name)
38163878
.map_or_else(|| planned_type_name(ty, type_names), str::to_string),
3879+
TypeRef::Void
3880+
| TypeRef::Object
3881+
| TypeRef::Generic { .. }
3882+
| TypeRef::Array { .. }
3883+
| TypeRef::InlineRecord(_) => return None,
38173884
_ => planned_type_name(ty, type_names),
3818-
}
3885+
};
3886+
Some(name)
38193887
}
38203888

38213889
fn value_name(value: &Value) -> String {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#[win32]
2+
mod Test {
3+
const DIRECT_POINTER: *mut Windows::Win32::IDataObject = 1;
4+
const TEXT_CALLBACK: *mut i8 = -1;
5+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//! reference-default
2+
//! args -x c++ --target=x86_64-pc-windows-msvc -fms-extensions
3+
4+
typedef struct IDataObject IDataObject;
5+
typedef IDataObject* LPDATAOBJECT;
6+
typedef LPDATAOBJECT DATAOBJECTPTR;
7+
typedef DATAOBJECTPTR DATAOBJECTPTR2;
8+
9+
#define DOBJ_NULL ((LPDATAOBJECT)0)
10+
#define DOBJ_CUSTOMOCX ((LPDATAOBJECT)-1)
11+
#define DOBJ_CUSTOMWEB ((DATAOBJECTPTR2)-2)
12+
#define TEXT_CALLBACK ((char*)-1)
13+
#define DIRECT_POINTER ((IDataObject*)1)

docs/crates/windows-clang.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ while their referenced types still participate in dependency closure.
205205

206206
Native NaN and infinity constants are omitted because RDL and ECMA metadata cannot represent them.
207207
This includes `f64` values that become non-finite when narrowed to their declared `f32` type.
208+
Integer-valued pointer constants remain supported. If a typedef chain resolves to an
209+
interface-pointer alias that is projected as the interface itself, constants declared with that
210+
typedef are omitted because ECMA metadata cannot encode an interface-valued constant. An explicit
211+
pointer to the same interface remains a pointer and is emitted.
208212

209213
### Bit-field member scraping
210214

0 commit comments

Comments
 (0)