diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 6113580491ef9..cc0b110d2bc6f 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -61,6 +61,9 @@ expand_feature_removed = expand_glob_delegation_outside_impls = glob delegation is only supported in impls +expand_glob_delegation_traitless_qpath = + qualified path without a trait in glob delegation + expand_helper_attribute_name_invalid = `{$name}` cannot be a name of derive helper attribute diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index c883121fb4065..0be7403f25b17 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -449,6 +449,13 @@ pub(crate) struct GlobDelegationOutsideImpls { pub span: Span, } +#[derive(Diagnostic)] +#[diag(expand_glob_delegation_traitless_qpath)] +pub(crate) struct GlobDelegationTraitlessQpath { + #[primary_span] + pub span: Span, +} + // This used to be the `proc_macro_back_compat` lint (#83125). It was later // turned into a hard error. #[derive(Diagnostic)] diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 716bfc8c26b1e..a331d83aab00a 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1,8 +1,9 @@ use crate::base::*; use crate::config::StripUnconfigured; use crate::errors::{ - EmptyDelegationMac, GlobDelegationOutsideImpls, IncompleteParse, RecursionLimitReached, - RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind, + EmptyDelegationMac, GlobDelegationOutsideImpls, GlobDelegationTraitlessQpath, IncompleteParse, + RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported, UnsupportedKeyValue, + WrongFragmentKind, }; use crate::mbe::diagnostics::annotate_err_with_kind; use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod}; @@ -1989,6 +1990,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } None if let Some((deleg, item)) = node.delegation() => { let Some(suffixes) = &deleg.suffixes else { + let traitless_qself = + matches!(&deleg.qself, Some(qself) if qself.position == 0); let item = match node.to_annotatable() { Annotatable::ImplItem(item) => item, ann @ (Annotatable::Item(_) @@ -2000,6 +2003,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } _ => unreachable!(), }; + if traitless_qself { + let span = item.span; + self.cx.dcx().emit_err(GlobDelegationTraitlessQpath { span }); + return Default::default(); + } return self.collect_glob_delegation(item, Node::KIND).make_ast::(); }; diff --git a/tests/ui/delegation/glob-traitless-qpath.rs b/tests/ui/delegation/glob-traitless-qpath.rs new file mode 100644 index 0000000000000..abf4b3180ed21 --- /dev/null +++ b/tests/ui/delegation/glob-traitless-qpath.rs @@ -0,0 +1,11 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +struct S; + +impl S { + reuse ::*; //~ ERROR qualified path without a trait in glob delegation + reuse <()>::*; //~ ERROR qualified path without a trait in glob delegation +} + +fn main() {} diff --git a/tests/ui/delegation/glob-traitless-qpath.stderr b/tests/ui/delegation/glob-traitless-qpath.stderr new file mode 100644 index 0000000000000..e3257de347a76 --- /dev/null +++ b/tests/ui/delegation/glob-traitless-qpath.stderr @@ -0,0 +1,14 @@ +error: qualified path without a trait in glob delegation + --> $DIR/glob-traitless-qpath.rs:7:5 + | +LL | reuse ::*; + | ^^^^^^^^^^^^^^ + +error: qualified path without a trait in glob delegation + --> $DIR/glob-traitless-qpath.rs:8:5 + | +LL | reuse <()>::*; + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +