8068: Correctly handle `#[cfg]` on function parameters r=jonas-schievink a=jonas-schievink

Fixes https://github.com/rust-analyzer/rust-analyzer/issues/5649

Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
This commit is contained in:
bors[bot] 2021-03-17 17:36:13 +00:00 committed by GitHub
commit 4fa56e3ab1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 172 additions and 79 deletions

View file

@ -9,7 +9,7 @@ use crate::{
attr::Attrs, attr::Attrs,
body::Expander, body::Expander,
db::DefDatabase, db::DefDatabase,
item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem}, item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param},
type_ref::{TypeBound, TypeRef}, type_ref::{TypeBound, TypeRef},
visibility::RawVisibility, visibility::RawVisibility,
AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
@ -36,19 +36,38 @@ impl FunctionData {
pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> { pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
let loc = func.lookup(db); let loc = func.lookup(db);
let krate = loc.container.module(db).krate; let krate = loc.container.module(db).krate;
let crate_graph = db.crate_graph();
let cfg_options = &crate_graph[krate].cfg_options;
let item_tree = db.item_tree(loc.id.file_id); let item_tree = db.item_tree(loc.id.file_id);
let func = &item_tree[loc.id.value]; let func = &item_tree[loc.id.value];
let enabled_params = func
.params
.clone()
.filter(|&param| item_tree.attrs(db, krate, param.into()).is_cfg_enabled(cfg_options));
// If last cfg-enabled param is a `...` param, it's a varargs function.
let is_varargs = enabled_params
.clone()
.next_back()
.map_or(false, |param| matches!(item_tree[param], Param::Varargs));
Arc::new(FunctionData { Arc::new(FunctionData {
name: func.name.clone(), name: func.name.clone(),
params: func.params.iter().map(|id| item_tree[*id].clone()).collect(), params: enabled_params
.clone()
.filter_map(|id| match &item_tree[id] {
Param::Normal(ty) => Some(item_tree[*ty].clone()),
Param::Varargs => None,
})
.collect(),
ret_type: item_tree[func.ret_type].clone(), ret_type: item_tree[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()),
has_self_param: func.has_self_param, has_self_param: func.has_self_param,
has_body: func.has_body, has_body: func.has_body,
qualifier: func.qualifier.clone(), qualifier: func.qualifier.clone(),
is_in_extern_block: func.is_in_extern_block, is_in_extern_block: func.is_in_extern_block,
is_varargs: func.is_varargs, is_varargs,
visibility: item_tree[func.visibility].clone(), visibility: item_tree[func.visibility].clone(),
}) })
} }

View file

@ -134,6 +134,7 @@ impl ItemTree {
imports, imports,
extern_crates, extern_crates,
functions, functions,
params,
structs, structs,
fields, fields,
unions, unions,
@ -157,6 +158,7 @@ impl ItemTree {
imports.shrink_to_fit(); imports.shrink_to_fit();
extern_crates.shrink_to_fit(); extern_crates.shrink_to_fit();
functions.shrink_to_fit(); functions.shrink_to_fit();
params.shrink_to_fit();
structs.shrink_to_fit(); structs.shrink_to_fit();
fields.shrink_to_fit(); fields.shrink_to_fit();
unions.shrink_to_fit(); unions.shrink_to_fit();
@ -303,6 +305,7 @@ struct ItemTreeData {
imports: Arena<Import>, imports: Arena<Import>,
extern_crates: Arena<ExternCrate>, extern_crates: Arena<ExternCrate>,
functions: Arena<Function>, functions: Arena<Function>,
params: Arena<Param>,
structs: Arena<Struct>, structs: Arena<Struct>,
fields: Arena<Field>, fields: Arena<Field>,
unions: Arena<Union>, unions: Arena<Union>,
@ -334,6 +337,7 @@ pub enum AttrOwner {
Variant(Idx<Variant>), Variant(Idx<Variant>),
Field(Idx<Field>), Field(Idx<Field>),
Param(Idx<Param>),
} }
macro_rules! from_attrs { macro_rules! from_attrs {
@ -348,7 +352,7 @@ macro_rules! from_attrs {
}; };
} }
from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>)); from_attrs!(ModItem(ModItem), Variant(Idx<Variant>), Field(Idx<Field>), Param(Idx<Param>));
/// Trait implemented by all item nodes in the item tree. /// Trait implemented by all item nodes in the item tree.
pub trait ItemTreeNode: Clone { pub trait ItemTreeNode: Clone {
@ -484,7 +488,7 @@ macro_rules! impl_index {
}; };
} }
impl_index!(fields: Field, variants: Variant); impl_index!(fields: Field, variants: Variant, params: Param);
impl Index<RawVisibilityId> for ItemTree { impl Index<RawVisibilityId> for ItemTree {
type Output = RawVisibility; type Output = RawVisibility;
@ -560,12 +564,17 @@ pub struct Function {
/// Whether the function is located in an `extern` block (*not* whether it is an /// Whether the function is located in an `extern` block (*not* whether it is an
/// `extern "abi" fn`). /// `extern "abi" fn`).
pub is_in_extern_block: bool, pub is_in_extern_block: bool,
pub params: Box<[Idx<TypeRef>]>, pub params: IdRange<Param>,
pub is_varargs: bool,
pub ret_type: Idx<TypeRef>, pub ret_type: Idx<TypeRef>,
pub ast_id: FileAstId<ast::Fn>, pub ast_id: FileAstId<ast::Fn>,
} }
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Param {
Normal(Idx<TypeRef>),
Varargs,
}
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionQualifier { pub struct FunctionQualifier {
pub is_default: bool, pub is_default: bool,
@ -796,6 +805,7 @@ pub struct Variant {
pub fields: Fields, pub fields: Fields,
} }
/// A range of densely allocated ItemTree IDs.
pub struct IdRange<T> { pub struct IdRange<T> {
range: Range<u32>, range: Range<u32>,
_p: PhantomData<T>, _p: PhantomData<T>,
@ -814,6 +824,12 @@ impl<T> Iterator for IdRange<T> {
} }
} }
impl<T> DoubleEndedIterator for IdRange<T> {
fn next_back(&mut self) -> Option<Self::Item> {
self.range.next_back().map(|raw| Idx::from_raw(raw.into()))
}
}
impl<T> fmt::Debug for IdRange<T> { impl<T> fmt::Debug for IdRange<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple(&format!("IdRange::<{}>", type_name::<T>())).field(&self.range).finish() f.debug_tuple(&format!("IdRange::<{}>", type_name::<T>())).field(&self.range).finish()

View file

@ -333,8 +333,8 @@ impl Ctx {
let visibility = self.lower_visibility(func); let visibility = self.lower_visibility(func);
let name = func.name()?.as_name(); let name = func.name()?.as_name();
let mut params = Vec::new();
let mut has_self_param = false; let mut has_self_param = false;
let start_param = self.next_param_idx();
if let Some(param_list) = func.param_list() { if let Some(param_list) = func.param_list() {
if let Some(self_param) = param_list.self_param() { if let Some(self_param) = param_list.self_param() {
let self_type = match self_param.ty() { let self_type = match self_param.ty() {
@ -356,22 +356,25 @@ impl Ctx {
} }
} }
}; };
params.push(self_type); let ty = self.data().type_refs.intern(self_type);
let idx = self.data().params.alloc(Param::Normal(ty));
self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene));
has_self_param = true; has_self_param = true;
} }
for param in param_list.params() { for param in param_list.params() {
let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); let idx = match param.dotdotdot_token() {
params.push(type_ref); Some(_) => self.data().params.alloc(Param::Varargs),
} None => {
} let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
let params = params.into_iter().map(|param| self.data().type_refs.intern(param)).collect(); let ty = self.data().type_refs.intern(type_ref);
self.data().params.alloc(Param::Normal(ty))
let mut is_varargs = false; }
if let Some(params) = func.param_list() { };
if let Some(last) = params.params().last() { self.add_attrs(idx.into(), RawAttrs::new(&param, &self.hygiene));
is_varargs = last.dotdotdot_token().is_some();
} }
} }
let end_param = self.next_param_idx();
let params = IdRange::new(start_param..end_param);
let ret_type = match func.ret_type().and_then(|rt| rt.ty()) { let ret_type = match func.ret_type().and_then(|rt| rt.ty()) {
Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref), Some(type_ref) => TypeRef::from_ast(&self.body_ctx, type_ref),
@ -419,7 +422,6 @@ impl Ctx {
qualifier, qualifier,
is_in_extern_block: false, is_in_extern_block: false,
params, params,
is_varargs,
ret_type, ret_type,
ast_id, ast_id,
}; };
@ -682,9 +684,11 @@ impl Ctx {
GenericsOwner::Function(func) => { GenericsOwner::Function(func) => {
generics.fill(&self.body_ctx, sm, node); generics.fill(&self.body_ctx, sm, node);
// lower `impl Trait` in arguments // lower `impl Trait` in arguments
for param in &*func.params { for id in func.params.clone() {
let param = self.data().type_refs.lookup(*param); if let Param::Normal(ty) = self.data().params[id] {
generics.fill_implicit_impl_trait_args(param); let ty = self.data().type_refs.lookup(ty);
generics.fill_implicit_impl_trait_args(ty);
}
} }
} }
GenericsOwner::Struct GenericsOwner::Struct
@ -769,6 +773,11 @@ impl Ctx {
self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32), self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
)) ))
} }
fn next_param_idx(&self) -> Idx<Param> {
Idx::from_raw(RawIdx::from(
self.tree.data.as_ref().map_or(0, |data| data.params.len() as u32),
))
}
} }
fn desugar_future_path(orig: TypeRef) -> Path { fn desugar_future_path(orig: TypeRef) -> Path {

View file

@ -713,4 +713,38 @@ fn main() {
"#, "#,
); );
} }
#[test]
fn cfgd_out_fn_params() {
check_diagnostics(
r#"
fn foo(#[cfg(NEVER)] x: ()) {}
struct S;
impl S {
fn method(#[cfg(NEVER)] self) {}
fn method2(#[cfg(NEVER)] self, arg: u8) {}
fn method3(self, #[cfg(NEVER)] arg: u8) {}
}
extern "C" {
fn fixed(fixed: u8, #[cfg(NEVER)] ...);
fn varargs(#[cfg(not(NEVER))] ...);
}
fn main() {
foo();
S::method();
S::method2(0);
S::method3(S);
S.method3();
unsafe {
fixed(0);
varargs(1, 2, 3);
}
}
"#,
)
}
} }

View file

@ -41,22 +41,32 @@ fn list_(p: &mut Parser, flavor: Flavor) {
FnDef | FnTrait | FnPointer => (T!['('], T![')']), FnDef | FnTrait | FnPointer => (T!['('], T![')']),
}; };
let m = p.start(); let list_marker = p.start();
p.bump(bra); p.bump(bra);
let mut param_marker = None;
if let FnDef = flavor { if let FnDef = flavor {
// test self_param_outer_attr // test self_param_outer_attr
// fn f(#[must_use] self) {} // fn f(#[must_use] self) {}
let m = p.start(); let m = p.start();
attributes::outer_attrs(p); attributes::outer_attrs(p);
opt_self_param(p, m); match opt_self_param(p, m) {
Ok(()) => {}
Err(m) => param_marker = Some(m),
}
} }
while !p.at(EOF) && !p.at(ket) { while !p.at(EOF) && !p.at(ket) {
// test param_outer_arg // test param_outer_arg
// fn f(#[attr1] pat: Type) {} // fn f(#[attr1] pat: Type) {}
let m = p.start(); let m = match param_marker.take() {
attributes::outer_attrs(p); Some(m) => m,
None => {
let m = p.start();
attributes::outer_attrs(p);
m
}
};
if !p.at_ts(PARAM_FIRST) { if !p.at_ts(PARAM_FIRST) {
p.error("expected value parameter"); p.error("expected value parameter");
@ -72,8 +82,12 @@ fn list_(p: &mut Parser, flavor: Flavor) {
} }
} }
if let Some(m) = param_marker {
m.abandon(p);
}
p.expect(ket); p.expect(ket);
m.complete(p, PARAM_LIST); list_marker.complete(p, PARAM_LIST);
} }
const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST); const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);
@ -153,7 +167,7 @@ fn variadic_param(p: &mut Parser) -> bool {
// fn d(&'a mut self, x: i32) {} // fn d(&'a mut self, x: i32) {}
// fn e(mut self) {} // fn e(mut self) {}
// } // }
fn opt_self_param(p: &mut Parser, m: Marker) { fn opt_self_param(p: &mut Parser, m: Marker) -> Result<(), Marker> {
if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] { if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] {
p.eat(T![mut]); p.eat(T![mut]);
self_as_name(p); self_as_name(p);
@ -176,7 +190,7 @@ fn opt_self_param(p: &mut Parser, m: Marker) {
| (T![&], LIFETIME_IDENT, T![self], _) | (T![&], LIFETIME_IDENT, T![self], _)
| (T![&], LIFETIME_IDENT, T![mut], T![self]) | (T![&], LIFETIME_IDENT, T![mut], T![self])
) { ) {
return m.abandon(p); return Err(m);
} }
p.bump(T![&]); p.bump(T![&]);
if p.at(LIFETIME_IDENT) { if p.at(LIFETIME_IDENT) {
@ -189,6 +203,7 @@ fn opt_self_param(p: &mut Parser, m: Marker) {
if !p.at(T![')']) { if !p.at(T![')']) {
p.expect(T![,]); p.expect(T![,]);
} }
Ok(())
} }
fn self_as_name(p: &mut Parser) { fn self_as_name(p: &mut Parser) {

View file

@ -6,16 +6,16 @@ SOURCE_FILE@0..28
IDENT@3..4 "f" IDENT@3..4 "f"
PARAM_LIST@4..24 PARAM_LIST@4..24
L_PAREN@4..5 "(" L_PAREN@4..5 "("
ATTR@5..13 PARAM@5..23
POUND@5..6 "#" ATTR@5..13
L_BRACK@6..7 "[" POUND@5..6 "#"
PATH@7..12 L_BRACK@6..7 "["
PATH_SEGMENT@7..12 PATH@7..12
NAME_REF@7..12 PATH_SEGMENT@7..12
IDENT@7..12 "attr1" NAME_REF@7..12
R_BRACK@12..13 "]" IDENT@7..12 "attr1"
WHITESPACE@13..14 " " R_BRACK@12..13 "]"
PARAM@14..23 WHITESPACE@13..14 " "
IDENT_PAT@14..17 IDENT_PAT@14..17
NAME@14..17 NAME@14..17
IDENT@14..17 "pat" IDENT@14..17 "pat"

View file

@ -6,25 +6,25 @@ SOURCE_FILE@0..519
IDENT@3..5 "g1" IDENT@3..5 "g1"
PARAM_LIST@5..34 PARAM_LIST@5..34
L_PAREN@5..6 "(" L_PAREN@5..6 "("
ATTR@6..14 PARAM@6..33
POUND@6..7 "#" ATTR@6..14
L_BRACK@7..8 "[" POUND@6..7 "#"
PATH@8..13 L_BRACK@7..8 "["
PATH_SEGMENT@8..13 PATH@8..13
NAME_REF@8..13 PATH_SEGMENT@8..13
IDENT@8..13 "attr1" NAME_REF@8..13
R_BRACK@13..14 "]" IDENT@8..13 "attr1"
WHITESPACE@14..15 " " R_BRACK@13..14 "]"
ATTR@15..23 WHITESPACE@14..15 " "
POUND@15..16 "#" ATTR@15..23
L_BRACK@16..17 "[" POUND@15..16 "#"
PATH@17..22 L_BRACK@16..17 "["
PATH_SEGMENT@17..22 PATH@17..22
NAME_REF@17..22 PATH_SEGMENT@17..22
IDENT@17..22 "attr2" NAME_REF@17..22
R_BRACK@22..23 "]" IDENT@17..22 "attr2"
WHITESPACE@23..24 " " R_BRACK@22..23 "]"
PARAM@24..33 WHITESPACE@23..24 " "
IDENT_PAT@24..27 IDENT_PAT@24..27
NAME@24..27 NAME@24..27
IDENT@24..27 "pat" IDENT@24..27 "pat"
@ -48,16 +48,16 @@ SOURCE_FILE@0..519
IDENT@41..43 "g2" IDENT@41..43 "g2"
PARAM_LIST@43..59 PARAM_LIST@43..59
L_PAREN@43..44 "(" L_PAREN@43..44 "("
ATTR@44..52 PARAM@44..58
POUND@44..45 "#" ATTR@44..52
L_BRACK@45..46 "[" POUND@44..45 "#"
PATH@46..51 L_BRACK@45..46 "["
PATH_SEGMENT@46..51 PATH@46..51
NAME_REF@46..51 PATH_SEGMENT@46..51
IDENT@46..51 "attr1" NAME_REF@46..51
R_BRACK@51..52 "]" IDENT@46..51 "attr1"
WHITESPACE@52..53 " " R_BRACK@51..52 "]"
PARAM@53..58 WHITESPACE@52..53 " "
IDENT_PAT@53..54 IDENT_PAT@53..54
NAME@53..54 NAME@53..54
IDENT@53..54 "x" IDENT@53..54 "x"
@ -203,16 +203,16 @@ SOURCE_FILE@0..519
IDENT@193..196 "bar" IDENT@193..196 "bar"
PARAM_LIST@196..233 PARAM_LIST@196..233
L_PAREN@196..197 "(" L_PAREN@196..197 "("
ATTR@197..204 PARAM@197..211
POUND@197..198 "#" ATTR@197..204
L_BRACK@198..199 "[" POUND@197..198 "#"
PATH@199..203 L_BRACK@198..199 "["
PATH_SEGMENT@199..203 PATH@199..203
NAME_REF@199..203 PATH_SEGMENT@199..203
IDENT@199..203 "attr" NAME_REF@199..203
R_BRACK@203..204 "]" IDENT@199..203 "attr"
WHITESPACE@204..205 " " R_BRACK@203..204 "]"
PARAM@205..211 WHITESPACE@204..205 " "
WILDCARD_PAT@205..206 WILDCARD_PAT@205..206
UNDERSCORE@205..206 "_" UNDERSCORE@205..206 "_"
COLON@206..207 ":" COLON@206..207 ":"