Fix incorrect handling of cfg'd varargs

This commit is contained in:
Lukas Wirth 2024-07-25 11:02:19 +02:00
parent 9cbafa2d49
commit f2fa456a8c
8 changed files with 37 additions and 16 deletions

View file

@ -73,6 +73,17 @@ impl FunctionData {
flags.remove(FnFlags::HAS_SELF_PARAM); flags.remove(FnFlags::HAS_SELF_PARAM);
} }
} }
if flags.contains(FnFlags::IS_VARARGS) {
if let Some((_, param)) = func.params.iter().enumerate().rev().find(|&(idx, _)| {
item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
}) {
if param.type_ref.is_some() {
flags.remove(FnFlags::IS_VARARGS);
}
} else {
flags.remove(FnFlags::IS_VARARGS);
}
}
let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()); let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
let legacy_const_generics_indices = attrs let legacy_const_generics_indices = attrs
@ -92,7 +103,7 @@ impl FunctionData {
.filter(|&(idx, _)| { .filter(|&(idx, _)| {
item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options) item_tree.attrs(db, krate, attr_owner(idx)).is_cfg_enabled(cfg_options)
}) })
.map(|(_, param)| param.type_ref.clone()) .filter_map(|(_, param)| param.type_ref.clone())
.collect(), .collect(),
ret_type: func.ret_type.clone(), ret_type: func.ret_type.clone(),
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),

View file

@ -741,7 +741,7 @@ pub struct Function {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Param { pub struct Param {
pub type_ref: Interned<TypeRef>, pub type_ref: Option<Interned<TypeRef>>,
} }
bitflags::bitflags! { bitflags::bitflags! {

View file

@ -380,7 +380,7 @@ impl<'a> Ctx<'a> {
} }
}; };
let type_ref = Interned::new(self_type); let type_ref = Interned::new(self_type);
params.push(Param { type_ref }); params.push(Param { type_ref: Some(type_ref) });
has_self_param = true; has_self_param = true;
} }
for param in param_list.params() { for param in param_list.params() {
@ -388,12 +388,12 @@ impl<'a> Ctx<'a> {
let param = match param.dotdotdot_token() { let param = match param.dotdotdot_token() {
Some(_) => { Some(_) => {
has_var_args = true; has_var_args = true;
Param { type_ref: Interned::new(TypeRef::Error) } Param { type_ref: None }
} }
None => { None => {
let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
let ty = Interned::new(type_ref); let ty = Interned::new(type_ref);
Param { type_ref: ty } Param { type_ref: Some(ty) }
} }
}; };
params.push(param); params.push(param);

View file

@ -291,7 +291,7 @@ impl Printer<'_> {
if idx == 0 && flags.contains(FnFlags::HAS_SELF_PARAM) { if idx == 0 && flags.contains(FnFlags::HAS_SELF_PARAM) {
w!(this, "self: "); w!(this, "self: ");
} }
if idx != params.len() { if let Some(type_ref) = type_ref {
this.print_type_ref(type_ref); this.print_type_ref(type_ref);
} else { } else {
wln!(this, "..."); wln!(this, "...");

View file

@ -812,9 +812,7 @@ impl<'a> InferenceContext<'a> {
None => self.err_ty(), None => self.err_ty(),
}; };
if let Some(ty) = param_tys.last_mut() { param_tys.push(va_list_ty);
*ty = va_list_ty;
}
} }
let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.new_type_var())); let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.new_type_var()));
if let Some(self_param) = self.body.self_param { if let Some(self_param) = self.body.self_param {

View file

@ -1126,6 +1126,23 @@ fn var_args() {
pub struct VaListImpl<'f>; pub struct VaListImpl<'f>;
fn my_fn(foo: ...) {} fn my_fn(foo: ...) {}
//^^^ VaListImpl<'?> //^^^ VaListImpl<'?>
fn my_fn2(bar: u32, foo: ...) {}
//^^^ VaListImpl<'?>
"#,
);
}
#[test]
fn var_args_cond() {
check_types(
r#"
#[lang = "va_list"]
pub struct VaListImpl<'f>;
fn my_fn(bar: u32, #[cfg(FALSE)] foo: ..., #[cfg(not(FALSE))] foo: u32) {
foo;
//^^^ u32
}
"#, "#,
); );
} }

View file

@ -99,13 +99,7 @@ impl HirDisplay for Function {
} }
// FIXME: Use resolved `param.ty` once we no longer discard lifetimes // FIXME: Use resolved `param.ty` once we no longer discard lifetimes
for (type_ref, param) in data for (type_ref, param) in data.params.iter().zip(self.assoc_fn_params(db)).skip(skip_self) {
.params
.iter()
.zip(self.assoc_fn_params(db))
.take(data.params.len() - data.is_varargs() as usize)
.skip(skip_self)
{
let local = param.as_local(db).map(|it| it.name(db)); let local = param.as_local(db).map(|it| it.name(db));
if !first { if !first {
f.write_str(", ")?; f.write_str(", ")?;

View file

@ -56,6 +56,7 @@ macro_rules! define_symbols {
define_symbols! { define_symbols! {
@WITH_NAME: @WITH_NAME:
dotdotdot = "...",
INTEGER_0 = "0", INTEGER_0 = "0",
INTEGER_1 = "1", INTEGER_1 = "1",
INTEGER_2 = "2", INTEGER_2 = "2",