Unnamed repository; edit this file 'description' to name the repository.
Handle more cases of cfgs in expr store lowering:
- Closure parameters - Tuple fields - Inline asm options - And the cursed of all, macros that expand into a disabled cfg. Amusingly (and thankfully), unlike expressions patterns do not support cfgs in those places, the only place they do is record fields, and they don't have macros.
Chayim Refael Friedman 13 days ago
parent bd24a5d · commit 433f90e
-rw-r--r--crates/hir-def/src/expr_store/lower.rs20
-rw-r--r--crates/hir-def/src/expr_store/lower/asm.rs4
-rw-r--r--crates/hir-def/src/expr_store/tests/body.rs45
-rw-r--r--crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs17
-rw-r--r--crates/parser/src/grammar/expressions/atom.rs4
-rw-r--r--crates/parser/test_data/generated/runner.rs4
-rw-r--r--crates/parser/test_data/parser/inline/ok/asm_piece_attr.rast29
-rw-r--r--crates/parser/test_data/parser/inline/ok/asm_piece_attr.rs1
-rw-r--r--crates/syntax/rust.ungram6
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs19
10 files changed, 136 insertions, 13 deletions
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index a69755baf6..afbcf4cc84 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -1562,6 +1562,10 @@ impl<'db> ExprCollector<'db> {
args.reserve_exact(num_params);
arg_types.reserve_exact(num_params);
for param in pl.params() {
+ if !this.check_cfg(&param) {
+ continue;
+ }
+
let pat = this.collect_pat_top(param.pat());
let type_ref =
param.ty().map(|it| this.lower_type_ref_disallow_impl_trait(it));
@@ -1666,7 +1670,7 @@ impl<'db> ExprCollector<'db> {
}
}
ast::Expr::TupleExpr(e) => {
- let mut exprs: Vec<_> = e.fields().map(|expr| self.collect_expr(expr)).collect();
+ let mut exprs: Vec<_> = e.fields().filter_map(|expr| self.maybe_collect_expr(expr)).collect();
// if there is a leading comma, the user is most likely to type out a leading expression
// so we insert a missing expression at the beginning for IDE features
if comma_follows_token(e.l_paren_token()) {
@@ -1681,13 +1685,7 @@ impl<'db> ExprCollector<'db> {
match kind {
ArrayExprKind::ElementList(e) => {
let elements = e
- .filter_map(|expr| {
- if self.check_cfg(&expr) {
- Some(self.collect_expr(expr))
- } else {
- None
- }
- })
+ .filter_map(|expr| self.maybe_collect_expr(expr))
.collect();
self.alloc_expr(Expr::Array(Array::ElementList { elements }), syntax_ptr)
}
@@ -1728,16 +1726,18 @@ impl<'db> ExprCollector<'db> {
let e = e.macro_call()?;
let macro_ptr = AstPtr::new(&e);
let id = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
- expansion.map(|it| this.collect_expr(it))
+ expansion.map(|it| this.maybe_collect_expr(it))
});
match id {
- Some(id) => {
+ Some(Some(id)) => {
// Make the macro-call point to its expanded expression so we can query
// semantics on syntax pointers to the macro
let src = self.expander.in_file(syntax_ptr);
self.store.expr_map.insert(src, id.into());
id
}
+ // Macro expanded into a disabled cfg (yes, there is such thing, see the weird_cfgs test).
+ Some(None) => return None,
None => self.alloc_expr(Expr::Missing, syntax_ptr),
}
}
diff --git a/crates/hir-def/src/expr_store/lower/asm.rs b/crates/hir-def/src/expr_store/lower/asm.rs
index 230d1c9346..63a0594f74 100644
--- a/crates/hir-def/src/expr_store/lower/asm.rs
+++ b/crates/hir-def/src/expr_store/lower/asm.rs
@@ -27,6 +27,10 @@ impl ExprCollector<'_> {
let mut named_args: FxHashMap<Symbol, usize> = Default::default();
let mut reg_args: FxHashSet<usize> = Default::default();
for piece in asm.asm_pieces() {
+ if !self.check_cfg(&piece) {
+ continue;
+ }
+
let slot = operands.len();
let mut lower_reg = |reg: Option<ast::AsmRegSpec>| {
let reg = reg?;
diff --git a/crates/hir-def/src/expr_store/tests/body.rs b/crates/hir-def/src/expr_store/tests/body.rs
index 98cbcb2450..dda5a8189c 100644
--- a/crates/hir-def/src/expr_store/tests/body.rs
+++ b/crates/hir-def/src/expr_store/tests/body.rs
@@ -716,3 +716,48 @@ fn foo() -> i64 {
}"#]],
);
}
+
+#[test]
+fn weird_cfgs() {
+ pretty_print(
+ r#"
+macro_rules! falsify {
+ ( $($t:tt)* ) => { #[cfg(false)] $($t)* };
+}
+
+struct Foo();
+
+fn foo() {
+ foo(falsify!(1));
+ (falsify!(1),);
+ [falsify!(1)];
+ Foo(falsify!(1));
+ foo(#[cfg(false)] 1);
+ (#[cfg(false)] 1,);
+ [#[cfg(false)] 1];
+ Foo(#[cfg(false)] 1);
+ (|#[cfg(false)] a| {})();
+
+ builtin # asm(
+ "",
+ #[cfg(false)] x = const 4,
+ #[cfg(false)] options(),
+ #[cfg(false)] clobber_abi("C"),
+ );
+}
+ "#,
+ expect![[r#"
+ fn foo() {
+ foo();
+ ();
+ [];
+ Foo();
+ foo();
+ ();
+ [];
+ Foo();
+ (|| {})();
+ builtin#asm(_);
+ }"#]],
+ );
+}
diff --git a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index d1c3d1c5df..81ea442e9e 100644
--- a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -539,4 +539,21 @@ pub fn repro<T: A>() {
"#,
);
}
+
+ #[test]
+ fn cfg_inside_macro_inside_arg() {
+ check_diagnostics(
+ r#"
+fn foo() {}
+
+macro_rules! make_X {
+ () => { #[cfg(false)] X };
+}
+
+fn main() {
+ foo(make_X!());
+}
+ "#,
+ );
+ }
}
diff --git a/crates/parser/src/grammar/expressions/atom.rs b/crates/parser/src/grammar/expressions/atom.rs
index bc7db630d1..7ce1fc2c48 100644
--- a/crates/parser/src/grammar/expressions/atom.rs
+++ b/crates/parser/src/grammar/expressions/atom.rs
@@ -355,6 +355,10 @@ pub(crate) fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedM
}
let op_n = p.start();
+ // test asm_piece_attr
+ // builtin # global_asm("", #[cfg(false)] options())
+ attributes::outer_attrs(p);
+
// Parse clobber_abi
if p.eat_contextual_kw(T![clobber_abi]) {
parse_clobber_abi(p);
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index 26d28ddfc6..4901ece9ca 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -25,6 +25,10 @@ mod ok {
#[test]
fn asm_label() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_label.rs"); }
#[test]
+ fn asm_piece_attr() {
+ run_and_expect_no_errors("test_data/parser/inline/ok/asm_piece_attr.rs");
+ }
+ #[test]
fn asm_sym_paren() { run_and_expect_no_errors("test_data/parser/inline/ok/asm_sym_paren.rs"); }
#[test]
fn assoc_const_eq() {
diff --git a/crates/parser/test_data/parser/inline/ok/asm_piece_attr.rast b/crates/parser/test_data/parser/inline/ok/asm_piece_attr.rast
new file mode 100644
index 0000000000..1fa9cd6dd7
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/asm_piece_attr.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+ ASM_EXPR
+ BUILTIN_KW "builtin"
+ WHITESPACE " "
+ POUND "#"
+ WHITESPACE " "
+ GLOBAL_ASM_KW "global_asm"
+ L_PAREN "("
+ LITERAL
+ STRING "\"\""
+ COMMA ","
+ WHITESPACE " "
+ ASM_OPTIONS
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ CFG_META
+ CFG_KW "cfg"
+ L_PAREN "("
+ CFG_ATOM
+ FALSE_KW "false"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE " "
+ OPTIONS_KW "options"
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/asm_piece_attr.rs b/crates/parser/test_data/parser/inline/ok/asm_piece_attr.rs
new file mode 100644
index 0000000000..ac9ad101d9
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/asm_piece_attr.rs
@@ -0,0 +1 @@
+builtin # global_asm("", #[cfg(false)] options())
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index e1c91c41e6..05df8b9b14 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -468,17 +468,17 @@ AsmRegSpec = '@string' | NameRef
// reg_operand := [ident "="] dir_spec "(" reg_spec ")" operand_expr
AsmRegOperand = AsmDirSpec '(' AsmRegSpec ')' AsmOperandExpr
// clobber_abi := "clobber_abi(" <abi> *("," <abi>) [","] ")"
-AsmClobberAbi = 'clobber_abi' '(' ('@string' (',' '@string')* ','?) ')'
+AsmClobberAbi = Attr* 'clobber_abi' '(' ('@string' (',' '@string')* ','?) ')'
// option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw"
AsmOption = 'pure' | 'nomem' | 'readonly' | 'preserves_flags' | 'noreturn' | 'nostack' | 'att_syntax' | 'raw' | 'may_unwind'
// options := "options(" option *("," option) [","] ")"
-AsmOptions = 'options' '(' (AsmOption (',' AsmOption)*) ','? ')'
+AsmOptions = Attr* 'options' '(' (AsmOption (',' AsmOption)*) ','? ')'
AsmLabel = 'label' BlockExpr
AsmSym = 'sym' Path
AsmConst = 'const' Expr
// operand := reg_operand / clobber_abi / options
AsmOperand = AsmRegOperand | AsmLabel | AsmSym | AsmConst
-AsmOperandNamed = (Name '=')? AsmOperand
+AsmOperandNamed = Attr* (Name '=')? AsmOperand
AsmPiece = AsmOperandNamed | AsmClobberAbi | AsmOptions
FormatArgsExpr =
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index ac1cddf74c..e0992ab9cf 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -59,6 +59,7 @@ impl ArrayType {
pub struct AsmClobberAbi {
pub(crate) syntax: SyntaxNode,
}
+impl ast::HasAttrs for AsmClobberAbi {}
impl AsmClobberAbi {
#[inline]
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
@@ -150,6 +151,7 @@ impl AsmOperandExpr {
pub struct AsmOperandNamed {
pub(crate) syntax: SyntaxNode,
}
+impl ast::HasAttrs for AsmOperandNamed {}
impl ast::HasName for AsmOperandNamed {}
impl AsmOperandNamed {
#[inline]
@@ -193,6 +195,7 @@ impl AsmOption {
pub struct AsmOptions {
pub(crate) syntax: SyntaxNode,
}
+impl ast::HasAttrs for AsmOptions {}
impl AsmOptions {
#[inline]
pub fn asm_options(&self) -> AstChildren<AsmOption> { support::children(&self.syntax) }
@@ -2193,6 +2196,7 @@ pub enum AsmPiece {
AsmOperandNamed(AsmOperandNamed),
AsmOptions(AsmOptions),
}
+impl ast::HasAttrs for AsmPiece {}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum AssocItem {
@@ -9096,7 +9100,10 @@ impl AstNode for AnyHasAttrs {
matches!(
kind,
ARRAY_EXPR
+ | ASM_CLOBBER_ABI
| ASM_EXPR
+ | ASM_OPERAND_NAMED
+ | ASM_OPTIONS
| ASSOC_ITEM_LIST
| AWAIT_EXPR
| BECOME_EXPR
@@ -9194,10 +9201,22 @@ impl From<ArrayExpr> for AnyHasAttrs {
#[inline]
fn from(node: ArrayExpr) -> AnyHasAttrs { AnyHasAttrs { syntax: node.syntax } }
}
+impl From<AsmClobberAbi> for AnyHasAttrs {
+ #[inline]
+ fn from(node: AsmClobberAbi) -> AnyHasAttrs { AnyHasAttrs { syntax: node.syntax } }
+}
impl From<AsmExpr> for AnyHasAttrs {
#[inline]
fn from(node: AsmExpr) -> AnyHasAttrs { AnyHasAttrs { syntax: node.syntax } }
}
+impl From<AsmOperandNamed> for AnyHasAttrs {
+ #[inline]
+ fn from(node: AsmOperandNamed) -> AnyHasAttrs { AnyHasAttrs { syntax: node.syntax } }
+}
+impl From<AsmOptions> for AnyHasAttrs {
+ #[inline]
+ fn from(node: AsmOptions) -> AnyHasAttrs { AnyHasAttrs { syntax: node.syntax } }
+}
impl From<AssocItemList> for AnyHasAttrs {
#[inline]
fn from(node: AssocItemList) -> AnyHasAttrs { AnyHasAttrs { syntax: node.syntax } }