Rollup merge of #137565 - compiler-errors:macro-ex, r=estebank
Try to point of macro expansion from resolver and method errors if it involves macro var In the case that a macro caller passes an identifier into a macro generating a path or method expression, point out that identifier in the context of the *macro* so it's a bit more clear how the macro is involved in causing the error. r? ``````````@estebank`````````` or reassign
This commit is contained in:
commit
aab7b145d0
17 changed files with 225 additions and 15 deletions
|
@ -617,6 +617,8 @@ hir_analysis_variances_of = {$variances}
|
||||||
hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause
|
hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause
|
||||||
.label = `main` cannot have a `where` clause
|
.label = `main` cannot have a `where` clause
|
||||||
|
|
||||||
|
hir_analysis_within_macro = due to this macro variable
|
||||||
|
|
||||||
hir_analysis_wrong_number_of_generic_arguments_to_intrinsic =
|
hir_analysis_wrong_number_of_generic_arguments_to_intrinsic =
|
||||||
intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected}
|
intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected}
|
||||||
.label = expected {$expected} {$descr} {$expected ->
|
.label = expected {$expected} {$descr} {$expected ->
|
||||||
|
|
|
@ -82,6 +82,8 @@ pub(crate) struct AssocItemNotFound<'a> {
|
||||||
pub label: Option<AssocItemNotFoundLabel<'a>>,
|
pub label: Option<AssocItemNotFoundLabel<'a>>,
|
||||||
#[subdiagnostic]
|
#[subdiagnostic]
|
||||||
pub sugg: Option<AssocItemNotFoundSugg<'a>>,
|
pub sugg: Option<AssocItemNotFoundSugg<'a>>,
|
||||||
|
#[label(hir_analysis_within_macro)]
|
||||||
|
pub within_macro_span: Option<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Subdiagnostic)]
|
#[derive(Subdiagnostic)]
|
||||||
|
|
|
@ -151,6 +151,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||||
qself: &qself_str,
|
qself: &qself_str,
|
||||||
label: None,
|
label: None,
|
||||||
sugg: None,
|
sugg: None,
|
||||||
|
// Try to get the span of the identifier within the path's syntax context
|
||||||
|
// (if that's different).
|
||||||
|
within_macro_span: assoc_name.span.within_macro(span, tcx.sess.source_map()),
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_dummy {
|
if is_dummy {
|
||||||
|
|
|
@ -3069,7 +3069,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
"ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, base_ty={:?}",
|
"ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, base_ty={:?}",
|
||||||
ident, base, expr, base_ty
|
ident, base, expr, base_ty
|
||||||
);
|
);
|
||||||
let mut err = self.no_such_field_err(ident, base_ty, base.hir_id);
|
let mut err = self.no_such_field_err(ident, base_ty, expr);
|
||||||
|
|
||||||
match *base_ty.peel_refs().kind() {
|
match *base_ty.peel_refs().kind() {
|
||||||
ty::Array(_, len) => {
|
ty::Array(_, len) => {
|
||||||
|
@ -3282,18 +3282,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn no_such_field_err(&self, field: Ident, expr_t: Ty<'tcx>, id: HirId) -> Diag<'_> {
|
fn no_such_field_err(
|
||||||
|
&self,
|
||||||
|
field: Ident,
|
||||||
|
base_ty: Ty<'tcx>,
|
||||||
|
expr: &hir::Expr<'tcx>,
|
||||||
|
) -> Diag<'_> {
|
||||||
let span = field.span;
|
let span = field.span;
|
||||||
debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t);
|
debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, base_ty);
|
||||||
|
|
||||||
let mut err = self.dcx().create_err(NoFieldOnType { span, ty: expr_t, field });
|
let mut err = self.dcx().create_err(NoFieldOnType { span, ty: base_ty, field });
|
||||||
if expr_t.references_error() {
|
if base_ty.references_error() {
|
||||||
err.downgrade_to_delayed_bug();
|
err.downgrade_to_delayed_bug();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(within_macro_span) = span.within_macro(expr.span, self.tcx.sess.source_map()) {
|
||||||
|
err.span_label(within_macro_span, "due to this macro variable");
|
||||||
|
}
|
||||||
|
|
||||||
// try to add a suggestion in case the field is a nested field of a field of the Adt
|
// try to add a suggestion in case the field is a nested field of a field of the Adt
|
||||||
let mod_id = self.tcx.parent_module(id).to_def_id();
|
let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id();
|
||||||
let (ty, unwrap) = if let ty::Adt(def, args) = expr_t.kind()
|
let (ty, unwrap) = if let ty::Adt(def, args) = base_ty.kind()
|
||||||
&& (self.tcx.is_diagnostic_item(sym::Result, def.did())
|
&& (self.tcx.is_diagnostic_item(sym::Result, def.did())
|
||||||
|| self.tcx.is_diagnostic_item(sym::Option, def.did()))
|
|| self.tcx.is_diagnostic_item(sym::Option, def.did()))
|
||||||
&& let Some(arg) = args.get(0)
|
&& let Some(arg) = args.get(0)
|
||||||
|
@ -3301,10 +3310,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
{
|
{
|
||||||
(ty, "unwrap().")
|
(ty, "unwrap().")
|
||||||
} else {
|
} else {
|
||||||
(expr_t, "")
|
(base_ty, "")
|
||||||
};
|
};
|
||||||
for (found_fields, args) in
|
for (found_fields, args) in
|
||||||
self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, id)
|
self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, expr.hir_id)
|
||||||
{
|
{
|
||||||
let field_names = found_fields.iter().map(|field| field.name).collect::<Vec<_>>();
|
let field_names = found_fields.iter().map(|field| field.name).collect::<Vec<_>>();
|
||||||
let mut candidate_fields: Vec<_> = found_fields
|
let mut candidate_fields: Vec<_> = found_fields
|
||||||
|
@ -3317,7 +3326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
args,
|
args,
|
||||||
vec![],
|
vec![],
|
||||||
mod_id,
|
mod_id,
|
||||||
id,
|
expr.hir_id,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map(|mut field_path| {
|
.map(|mut field_path| {
|
||||||
|
@ -3328,7 +3337,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
candidate_fields.sort();
|
candidate_fields.sort();
|
||||||
|
|
||||||
let len = candidate_fields.len();
|
let len = candidate_fields.len();
|
||||||
if len > 0 {
|
// Don't suggest `.field` if the base expr is from a different
|
||||||
|
// syntax context than the field.
|
||||||
|
if len > 0 && expr.span.eq_ctxt(field.span) {
|
||||||
err.span_suggestions(
|
err.span_suggestions(
|
||||||
field.span.shrink_to_lo(),
|
field.span.shrink_to_lo(),
|
||||||
format!(
|
format!(
|
||||||
|
@ -3963,7 +3974,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.no_such_field_err(field, container, expr.hir_id).emit();
|
self.no_such_field_err(field, container, expr).emit();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,7 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
self.typeck_results.borrow_mut().used_trait_imports.insert(import_id);
|
self.typeck_results.borrow_mut().used_trait_imports.insert(import_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (span, sugg_span, source, item_name, args) = match self.tcx.hir_node(call_id) {
|
let (span, expr_span, source, item_name, args) = match self.tcx.hir_node(call_id) {
|
||||||
hir::Node::Expr(&hir::Expr {
|
hir::Node::Expr(&hir::Expr {
|
||||||
kind: hir::ExprKind::MethodCall(segment, rcvr, args, _),
|
kind: hir::ExprKind::MethodCall(segment, rcvr, args, _),
|
||||||
span,
|
span,
|
||||||
|
@ -194,6 +194,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
node => unreachable!("{node:?}"),
|
node => unreachable!("{node:?}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Try to get the span of the identifier within the expression's syntax context
|
||||||
|
// (if that's different).
|
||||||
|
let within_macro_span = span.within_macro(expr_span, self.tcx.sess.source_map());
|
||||||
|
|
||||||
// Avoid suggestions when we don't know what's going on.
|
// Avoid suggestions when we don't know what's going on.
|
||||||
if let Err(guar) = rcvr_ty.error_reported() {
|
if let Err(guar) = rcvr_ty.error_reported() {
|
||||||
return guar;
|
return guar;
|
||||||
|
@ -207,10 +211,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
call_id,
|
call_id,
|
||||||
source,
|
source,
|
||||||
args,
|
args,
|
||||||
sugg_span,
|
expr_span,
|
||||||
&mut no_match_data,
|
&mut no_match_data,
|
||||||
expected,
|
expected,
|
||||||
trait_missing_method,
|
trait_missing_method,
|
||||||
|
within_macro_span,
|
||||||
),
|
),
|
||||||
|
|
||||||
MethodError::Ambiguity(mut sources) => {
|
MethodError::Ambiguity(mut sources) => {
|
||||||
|
@ -221,6 +226,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
"multiple applicable items in scope"
|
"multiple applicable items in scope"
|
||||||
);
|
);
|
||||||
err.span_label(item_name.span, format!("multiple `{item_name}` found"));
|
err.span_label(item_name.span, format!("multiple `{item_name}` found"));
|
||||||
|
if let Some(within_macro_span) = within_macro_span {
|
||||||
|
err.span_label(within_macro_span, "due to this macro variable");
|
||||||
|
}
|
||||||
|
|
||||||
self.note_candidates_on_method_error(
|
self.note_candidates_on_method_error(
|
||||||
rcvr_ty,
|
rcvr_ty,
|
||||||
|
@ -230,7 +238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
span,
|
span,
|
||||||
&mut err,
|
&mut err,
|
||||||
&mut sources,
|
&mut sources,
|
||||||
Some(sugg_span),
|
Some(expr_span),
|
||||||
);
|
);
|
||||||
err.emit()
|
err.emit()
|
||||||
}
|
}
|
||||||
|
@ -252,6 +260,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.span_if_local(def_id)
|
.span_if_local(def_id)
|
||||||
.unwrap_or_else(|| self.tcx.def_span(def_id));
|
.unwrap_or_else(|| self.tcx.def_span(def_id));
|
||||||
err.span_label(sp, format!("private {kind} defined here"));
|
err.span_label(sp, format!("private {kind} defined here"));
|
||||||
|
if let Some(within_macro_span) = within_macro_span {
|
||||||
|
err.span_label(within_macro_span, "due to this macro variable");
|
||||||
|
}
|
||||||
self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true);
|
self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true);
|
||||||
err.emit()
|
err.emit()
|
||||||
}
|
}
|
||||||
|
@ -268,6 +279,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if !needs_mut {
|
if !needs_mut {
|
||||||
err.span_label(bound_span, "this has a `Sized` requirement");
|
err.span_label(bound_span, "this has a `Sized` requirement");
|
||||||
}
|
}
|
||||||
|
if let Some(within_macro_span) = within_macro_span {
|
||||||
|
err.span_label(within_macro_span, "due to this macro variable");
|
||||||
|
}
|
||||||
if !candidates.is_empty() {
|
if !candidates.is_empty() {
|
||||||
let help = format!(
|
let help = format!(
|
||||||
"{an}other candidate{s} {were} found in the following trait{s}",
|
"{an}other candidate{s} {were} found in the following trait{s}",
|
||||||
|
@ -581,6 +595,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
no_match_data: &mut NoMatchData<'tcx>,
|
no_match_data: &mut NoMatchData<'tcx>,
|
||||||
expected: Expectation<'tcx>,
|
expected: Expectation<'tcx>,
|
||||||
trait_missing_method: bool,
|
trait_missing_method: bool,
|
||||||
|
within_macro_span: Option<Span>,
|
||||||
) -> ErrorGuaranteed {
|
) -> ErrorGuaranteed {
|
||||||
let mode = no_match_data.mode;
|
let mode = no_match_data.mode;
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
@ -721,6 +736,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
if tcx.sess.source_map().is_multiline(sugg_span) {
|
if tcx.sess.source_map().is_multiline(sugg_span) {
|
||||||
err.span_label(sugg_span.with_hi(span.lo()), "");
|
err.span_label(sugg_span.with_hi(span.lo()), "");
|
||||||
}
|
}
|
||||||
|
if let Some(within_macro_span) = within_macro_span {
|
||||||
|
err.span_label(within_macro_span, "due to this macro variable");
|
||||||
|
}
|
||||||
|
|
||||||
if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
|
if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
|
||||||
ty_str = short_ty_str;
|
ty_str = short_ty_str;
|
||||||
|
|
|
@ -429,6 +429,14 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
|
||||||
let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone());
|
let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone());
|
||||||
err.code(code);
|
err.code(code);
|
||||||
|
|
||||||
|
// Try to get the span of the identifier within the path's syntax context
|
||||||
|
// (if that's different).
|
||||||
|
if let Some(within_macro_span) =
|
||||||
|
base_error.span.within_macro(span, self.r.tcx.sess.source_map())
|
||||||
|
{
|
||||||
|
err.span_label(within_macro_span, "due to this macro variable");
|
||||||
|
}
|
||||||
|
|
||||||
self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg);
|
self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg);
|
||||||
self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
|
self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
|
||||||
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
|
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
|
||||||
|
|
|
@ -1057,6 +1057,37 @@ impl Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `Span` within the syntax context of "within". This is useful when
|
||||||
|
/// "self" is an expansion from a macro variable, since this can be used for
|
||||||
|
/// providing extra macro expansion context for certain errors.
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// macro_rules! m {
|
||||||
|
/// ($ident:ident) => { ($ident,) }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// m!(outer_ident);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// If "self" is the span of the outer_ident, and "within" is the span of the `($ident,)`
|
||||||
|
/// expr, then this will return the span of the `$ident` macro variable.
|
||||||
|
pub fn within_macro(self, within: Span, sm: &SourceMap) -> Option<Span> {
|
||||||
|
match Span::prepare_to_combine(self, within) {
|
||||||
|
// Only return something if it doesn't overlap with the original span,
|
||||||
|
// and the span isn't "imported" (i.e. from unavailable sources).
|
||||||
|
// FIXME: This does limit the usefulness of the error when the macro is
|
||||||
|
// from a foreign crate; we could also take into account `-Zmacro-backtrace`,
|
||||||
|
// which doesn't redact this span (but that would mean passing in even more
|
||||||
|
// args to this function, lol).
|
||||||
|
Ok((self_, _, parent))
|
||||||
|
if self_.hi < self.lo() || self.hi() < self_.lo && !sm.is_imported(within) =>
|
||||||
|
{
|
||||||
|
Some(Span::new(self_.lo, self_.hi, self_.ctxt, parent))
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn from_inner(self, inner: InnerSpan) -> Span {
|
pub fn from_inner(self, inner: InnerSpan) -> Span {
|
||||||
let span = self.data();
|
let span = self.data();
|
||||||
Span::new(
|
Span::new(
|
||||||
|
|
23
tests/ui/associated-types/ident-from-macro-expansion.rs
Normal file
23
tests/ui/associated-types/ident-from-macro-expansion.rs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
trait Trait {}
|
||||||
|
impl Trait for () {}
|
||||||
|
|
||||||
|
macro_rules! fully_qualified {
|
||||||
|
($id:ident) => {
|
||||||
|
<() as Trait>::$id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! type_dependent {
|
||||||
|
($t:ident, $id:ident) => {
|
||||||
|
T::$id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn t<T: Trait>() {
|
||||||
|
let x: fully_qualified!(Assoc);
|
||||||
|
//~^ ERROR cannot find associated type `Assoc` in trait `Trait`
|
||||||
|
let x: type_dependent!(T, Assoc);
|
||||||
|
//~^ ERROR associated type `Assoc` not found for `T`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
22
tests/ui/associated-types/ident-from-macro-expansion.stderr
Normal file
22
tests/ui/associated-types/ident-from-macro-expansion.stderr
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
error[E0576]: cannot find associated type `Assoc` in trait `Trait`
|
||||||
|
--> $DIR/ident-from-macro-expansion.rs:17:29
|
||||||
|
|
|
||||||
|
LL | <() as Trait>::$id
|
||||||
|
| --- due to this macro variable
|
||||||
|
...
|
||||||
|
LL | let x: fully_qualified!(Assoc);
|
||||||
|
| ^^^^^ not found in `Trait`
|
||||||
|
|
||||||
|
error[E0220]: associated type `Assoc` not found for `T`
|
||||||
|
--> $DIR/ident-from-macro-expansion.rs:19:31
|
||||||
|
|
|
||||||
|
LL | T::$id
|
||||||
|
| --- due to this macro variable
|
||||||
|
...
|
||||||
|
LL | let x: type_dependent!(T, Assoc);
|
||||||
|
| ^^^^^ associated type `Assoc` not found
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0220, E0576.
|
||||||
|
For more information about an error, try `rustc --explain E0220`.
|
|
@ -1,12 +1,18 @@
|
||||||
error[E0412]: cannot find type `FromOutside` in this scope
|
error[E0412]: cannot find type `FromOutside` in this scope
|
||||||
--> $DIR/generate-mod.rs:35:13
|
--> $DIR/generate-mod.rs:35:13
|
||||||
|
|
|
|
||||||
|
LL | type A = $FromOutside;
|
||||||
|
| ------------ due to this macro variable
|
||||||
|
...
|
||||||
LL | genmod!(FromOutside, Outer);
|
LL | genmod!(FromOutside, Outer);
|
||||||
| ^^^^^^^^^^^ not found in this scope
|
| ^^^^^^^^^^^ not found in this scope
|
||||||
|
|
||||||
error[E0412]: cannot find type `Outer` in this scope
|
error[E0412]: cannot find type `Outer` in this scope
|
||||||
--> $DIR/generate-mod.rs:35:26
|
--> $DIR/generate-mod.rs:35:26
|
||||||
|
|
|
|
||||||
|
LL | struct $Outer;
|
||||||
|
| ------ due to this macro variable
|
||||||
|
...
|
||||||
LL | genmod!(FromOutside, Outer);
|
LL | genmod!(FromOutside, Outer);
|
||||||
| ^^^^^ not found in this scope
|
| ^^^^^ not found in this scope
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,9 @@ error[E0425]: cannot find function `f` in this scope
|
||||||
LL | n!(f);
|
LL | n!(f);
|
||||||
| ----- in this macro invocation
|
| ----- in this macro invocation
|
||||||
...
|
...
|
||||||
|
LL | $j();
|
||||||
|
| -- due to this macro variable
|
||||||
|
...
|
||||||
LL | n!(f);
|
LL | n!(f);
|
||||||
| ^ not found in this scope
|
| ^ not found in this scope
|
||||||
|
|
|
|
||||||
|
@ -63,6 +66,9 @@ error[E0425]: cannot find function `f` in this scope
|
||||||
LL | n!(f);
|
LL | n!(f);
|
||||||
| ----- in this macro invocation
|
| ----- in this macro invocation
|
||||||
...
|
...
|
||||||
|
LL | $j();
|
||||||
|
| -- due to this macro variable
|
||||||
|
...
|
||||||
LL | f
|
LL | f
|
||||||
| ^ not found in this scope
|
| ^ not found in this scope
|
||||||
|
|
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
error[E0425]: cannot find value `x` in this scope
|
error[E0425]: cannot find value `x` in this scope
|
||||||
--> $DIR/macro-parameter-span.rs:11:9
|
--> $DIR/macro-parameter-span.rs:11:9
|
||||||
|
|
|
|
||||||
|
LL | $id
|
||||||
|
| --- due to this macro variable
|
||||||
|
...
|
||||||
LL | x
|
LL | x
|
||||||
| ^ not found in this scope
|
| ^ not found in this scope
|
||||||
|
|
||||||
|
|
|
@ -338,6 +338,9 @@ LL | no_curly__no_rhs_dollar__no_round!(a);
|
||||||
error[E0425]: cannot find value `a` in this scope
|
error[E0425]: cannot find value `a` in this scope
|
||||||
--> $DIR/syntax-errors.rs:152:37
|
--> $DIR/syntax-errors.rs:152:37
|
||||||
|
|
|
|
||||||
|
LL | ( $i:ident ) => { count($i) };
|
||||||
|
| -- due to this macro variable
|
||||||
|
...
|
||||||
LL | no_curly__rhs_dollar__no_round!(a);
|
LL | no_curly__rhs_dollar__no_round!(a);
|
||||||
| ^ not found in this scope
|
| ^ not found in this scope
|
||||||
|
|
||||||
|
|
18
tests/ui/methods/ident-from-macro-expansion.rs
Normal file
18
tests/ui/methods/ident-from-macro-expansion.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
macro_rules! dot {
|
||||||
|
($id:ident) => {
|
||||||
|
().$id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! dispatch {
|
||||||
|
($id:ident) => {
|
||||||
|
<()>::$id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
dot!(hello);
|
||||||
|
//~^ ERROR no method named `hello` found for unit type `()` in the current scope
|
||||||
|
dispatch!(hello);
|
||||||
|
//~^ ERROR no function or associated item named `hello` found for unit type `()` in the current scope
|
||||||
|
}
|
21
tests/ui/methods/ident-from-macro-expansion.stderr
Normal file
21
tests/ui/methods/ident-from-macro-expansion.stderr
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
error[E0599]: no method named `hello` found for unit type `()` in the current scope
|
||||||
|
--> $DIR/ident-from-macro-expansion.rs:14:10
|
||||||
|
|
|
||||||
|
LL | ().$id();
|
||||||
|
| --- due to this macro variable
|
||||||
|
...
|
||||||
|
LL | dot!(hello);
|
||||||
|
| ^^^^^ method not found in `()`
|
||||||
|
|
||||||
|
error[E0599]: no function or associated item named `hello` found for unit type `()` in the current scope
|
||||||
|
--> $DIR/ident-from-macro-expansion.rs:16:15
|
||||||
|
|
|
||||||
|
LL | <()>::$id();
|
||||||
|
| --- due to this macro variable
|
||||||
|
...
|
||||||
|
LL | dispatch!(hello);
|
||||||
|
| ^^^^^ function or associated item not found in `()`
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
19
tests/ui/structs/ident-from-macro-expansion.rs
Normal file
19
tests/ui/structs/ident-from-macro-expansion.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
struct Foo {
|
||||||
|
inner: Inner,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Inner {
|
||||||
|
y: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! access {
|
||||||
|
($expr:expr, $ident:ident) => {
|
||||||
|
$expr.$ident
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let k = Foo { inner: Inner { y: 0 } };
|
||||||
|
access!(k, y);
|
||||||
|
//~^ ERROR no field `y` on type `Foo`
|
||||||
|
}
|
14
tests/ui/structs/ident-from-macro-expansion.stderr
Normal file
14
tests/ui/structs/ident-from-macro-expansion.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error[E0609]: no field `y` on type `Foo`
|
||||||
|
--> $DIR/ident-from-macro-expansion.rs:17:16
|
||||||
|
|
|
||||||
|
LL | $expr.$ident
|
||||||
|
| ------ due to this macro variable
|
||||||
|
...
|
||||||
|
LL | access!(k, y);
|
||||||
|
| ^ unknown field
|
||||||
|
|
|
||||||
|
= note: available field is: `inner`
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0609`.
|
Loading…
Add table
Add a link
Reference in a new issue