Skip to content

Commit

Permalink
Resolve attributes in generic parameter position
Browse files Browse the repository at this point in the history
  • Loading branch information
petrochenkov committed Jul 21, 2019
1 parent 83dfe7b commit 83fdb8d
Show file tree
Hide file tree
Showing 17 changed files with 220 additions and 248 deletions.
3 changes: 3 additions & 0 deletions src/librustc/hir/map/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> {
}

fn visit_generic_param(&mut self, param: &'a GenericParam) {
if param.ident.as_str() == "placeholder" {
return self.visit_macro_invoc(param.id);
}
let name = param.ident.as_interned_str();
let def_path_data = match param.kind {
GenericParamKind::Lifetime { .. } => DefPathData::LifetimeNs(name),
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1070,4 +1070,11 @@ impl<'a, 'b> Visitor<'a> for BuildReducedGraphVisitor<'a, 'b> {
}
visit::walk_attribute(self, attr);
}

fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
if param.ident.as_str() == "placeholder" {
self.visit_invoc(param.id);
}
visit::walk_generic_param(self, param);
}
}
12 changes: 11 additions & 1 deletion src/librustc_resolve/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use syntax::ast::{self, Ident, ItemKind};
use syntax::attr::{self, StabilityLevel};
use syntax::ext::base::{self, Indeterminate};
use syntax::ext::base::{MacroKind, SyntaxExtension};
use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
use syntax::ext::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind};
use syntax::ext::hygiene::{self, ExpnId, ExpnInfo, ExpnKind};
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{emit_feature_err, is_builtin_attr_name};
Expand Down Expand Up @@ -236,6 +236,16 @@ impl<'a> base::Resolver for Resolver<'a> {
normal_module_def_id);
}

match invoc.fragment_kind {
AstFragmentKind::GenericParams => {
if let Res::Def(..) = res {
self.session.span_err(span, "expected an inert attribute, found an attribute macro");
return Ok(Some(self.dummy_ext(kind)));
}
}
_ => {}
}

Ok(Some(ext))
}

Expand Down
4 changes: 0 additions & 4 deletions src/libsyntax/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,6 @@ impl<'a> StripUnconfigured<'a> {
items.flat_map_in_place(|item| self.configure(item));
}

pub fn configure_generic_params(&mut self, params: &mut Vec<ast::GenericParam>) {
params.flat_map_in_place(|param| self.configure(param));
}

fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) {
match vdata {
ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) =>
Expand Down
24 changes: 24 additions & 0 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ pub enum Annotatable {
ForeignItem(P<ast::ForeignItem>),
Stmt(P<ast::Stmt>),
Expr(P<ast::Expr>),
// New
GenericParam(ast::GenericParam),
}

impl HasAttrs for Annotatable {
Expand All @@ -45,6 +47,7 @@ impl HasAttrs for Annotatable {
Annotatable::ForeignItem(ref foreign_item) => &foreign_item.attrs,
Annotatable::Stmt(ref stmt) => stmt.attrs(),
Annotatable::Expr(ref expr) => &expr.attrs,
Annotatable::GenericParam(ref param) => &param.attrs,
}
}

Expand All @@ -56,6 +59,7 @@ impl HasAttrs for Annotatable {
Annotatable::ForeignItem(foreign_item) => foreign_item.visit_attrs(f),
Annotatable::Stmt(stmt) => stmt.visit_attrs(f),
Annotatable::Expr(expr) => expr.visit_attrs(f),
Annotatable::GenericParam(param) => param.visit_attrs(f),
}
}
}
Expand All @@ -69,6 +73,7 @@ impl Annotatable {
Annotatable::ForeignItem(ref foreign_item) => foreign_item.span,
Annotatable::Stmt(ref stmt) => stmt.span,
Annotatable::Expr(ref expr) => expr.span,
Annotatable::GenericParam(..) => DUMMY_SP,
}
}

Expand Down Expand Up @@ -124,6 +129,13 @@ impl Annotatable {
}
}

pub fn expect_generic_param(self) -> ast::GenericParam {
match self {
Annotatable::GenericParam(i) => i,
_ => panic!("expected generic parameter")
}
}

pub fn derive_allowed(&self) -> bool {
match *self {
Annotatable::Item(ref item) => match item.node {
Expand Down Expand Up @@ -315,6 +327,10 @@ pub trait MacResult {
fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> {
None
}

fn make_generic_params(self: Box<Self>) -> Option<SmallVec<[ast::GenericParam; 1]>> {
None
}
}

macro_rules! make_MacEager {
Expand Down Expand Up @@ -515,6 +531,14 @@ impl MacResult for DummyResult {
fn make_ty(self: Box<DummyResult>) -> Option<P<ast::Ty>> {
Some(DummyResult::raw_ty(self.span, self.is_error))
}

fn make_generic_params(self: Box<DummyResult>) -> Option<SmallVec<[ast::GenericParam; 1]>> {
if self.expr_only {
None
} else {
Some(SmallVec::new())
}
}
}

/// A syntax extension kind.
Expand Down
29 changes: 25 additions & 4 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ ast_fragments! {
ForeignItems(SmallVec<[ast::ForeignItem; 1]>) {
"foreign item"; many fn flat_map_foreign_item; fn visit_foreign_item; fn make_foreign_items;
}
// New
GenericParams(SmallVec<[ast::GenericParam; 1]>) {
"generic parameter"; many fn flat_map_generic_param; fn visit_generic_param; fn make_generic_params;
}
}

impl AstFragmentKind {
Expand All @@ -181,6 +185,8 @@ impl AstFragmentKind {
),
AstFragmentKind::OptExpr =>
AstFragment::OptExpr(items.next().map(Annotatable::expect_expr)),
AstFragmentKind::GenericParams =>
AstFragment::GenericParams(items.map(Annotatable::expect_generic_param).collect()),
AstFragmentKind::Pat | AstFragmentKind::Ty =>
panic!("patterns and types aren't annotatable"),
}
Expand All @@ -189,7 +195,7 @@ impl AstFragmentKind {

pub struct Invocation {
pub kind: InvocationKind,
fragment_kind: AstFragmentKind,
pub fragment_kind: AstFragmentKind,
pub expansion_data: ExpansionData,
}

Expand Down Expand Up @@ -479,6 +485,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
Annotatable::Expr(mut expr) => {
Annotatable::Expr({ cfg.visit_expr(&mut expr); expr })
}
Annotatable::GenericParam(param) => {
Annotatable::GenericParam(cfg.flat_map_generic_param(param).pop().unwrap())
}
}
}

Expand Down Expand Up @@ -540,6 +549,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()),
Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
Annotatable::Expr(expr) => token::NtExpr(expr),
Annotatable::GenericParam(..) => panic!("unexpected annotatable")
})), DUMMY_SP).into();
let input = self.extract_proc_macro_attr_input(attr.tokens, span);
let tok_result = expander.expand(self.cx, span, input, item_tok);
Expand Down Expand Up @@ -623,6 +633,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
Annotatable::Expr(_) if self.cx.ecfg.proc_macro_hygiene() => return,
Annotatable::Stmt(_) => ("statements", sym::proc_macro_hygiene),
Annotatable::Expr(_) => ("expressions", sym::proc_macro_hygiene),
Annotatable::GenericParam(..) => panic!("unexpected annotatable"),
};
emit_feature_err(
self.cx.parse_sess,
Expand Down Expand Up @@ -679,6 +690,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
AstFragmentKind::TraitItems => return,
AstFragmentKind::ImplItems => return,
AstFragmentKind::ForeignItems => return,
AstFragmentKind::GenericParams => panic!("unexpected AST fragment kind"),
};
if self.cx.ecfg.proc_macro_hygiene() {
return
Expand Down Expand Up @@ -767,6 +779,7 @@ impl<'a> Parser<'a> {
},
AstFragmentKind::Ty => AstFragment::Ty(self.parse_ty()?),
AstFragmentKind::Pat => AstFragment::Pat(self.parse_pat(None)?),
AstFragmentKind::GenericParams => panic!("unexpected AST fragment kind"),
})
}

Expand Down Expand Up @@ -1220,9 +1233,17 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
}
}

fn visit_generic_params(&mut self, params: &mut Vec<ast::GenericParam>) {
self.cfg.configure_generic_params(params);
noop_visit_generic_params(params, self);
fn flat_map_generic_param(&mut self, param: ast::GenericParam) -> SmallVec<[ast::GenericParam; 1]> {
let mut param = configure!(self, param);

let (attr, traits, after_derive) = self.classify_item(&mut param);
if attr.is_some() || !traits.is_empty() {
return self.collect_attr(attr, traits, Annotatable::GenericParam(param),
AstFragmentKind::GenericParams, after_derive)
.make_generic_params();
}

noop_flat_map_generic_param(param, self)
}

fn visit_attribute(&mut self, at: &mut ast::Attribute) {
Expand Down
16 changes: 16 additions & 0 deletions src/libsyntax/ext/placeholders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ pub fn placeholder(kind: AstFragmentKind, id: ast::NodeId) -> AstFragment {
let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ThinVec::new()));
ast::Stmt { id, span, node: ast::StmtKind::Mac(mac) }
}]),
AstFragmentKind::GenericParams => AstFragment::GenericParams(smallvec![{
ast::GenericParam {
id,
ident: ast::Ident::from_str("placeholder"),
attrs: Default::default(),
bounds: Default::default(),
kind: ast::GenericParamKind::Lifetime,
}
}])
}
}

Expand Down Expand Up @@ -164,6 +173,13 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> {
stmts
}

fn flat_map_generic_param(&mut self, param: ast::GenericParam) -> SmallVec<[ast::GenericParam; 1]> {
if param.ident.as_str() == "placeholder" {
return self.remove(param.id).make_generic_params()
}
noop_flat_map_generic_param(param, self)
}

fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
match pat.node {
ast::PatKind::Mac(_) => *pat = self.remove(pat.id).make_pat(),
Expand Down
24 changes: 9 additions & 15 deletions src/libsyntax/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,8 @@ pub trait MutVisitor: Sized {
noop_visit_variant_data(vdata, self);
}

fn visit_generic_param(&mut self, param: &mut GenericParam) {
noop_visit_generic_param(param, self);
}

fn visit_generic_params(&mut self, params: &mut Vec<GenericParam>) {
noop_visit_generic_params(params, self);
fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
noop_flat_map_generic_param(param, self)
}

fn visit_tt(&mut self, tt: &mut TokenTree) {
Expand Down Expand Up @@ -421,7 +417,7 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
}
TyKind::BareFn(bft) => {
let BareFnTy { unsafety: _, abi: _, generic_params, decl } = bft.deref_mut();
vis.visit_generic_params(generic_params);
generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
vis.visit_fn_decl(decl);
}
TyKind::Tup(tys) => visit_vec(tys, |ty| vis.visit_ty(ty)),
Expand Down Expand Up @@ -702,8 +698,8 @@ pub fn noop_visit_param_bound<T: MutVisitor>(pb: &mut GenericBound, vis: &mut T)
}
}

pub fn noop_visit_generic_param<T: MutVisitor>(param: &mut GenericParam, vis: &mut T) {
let GenericParam { id, ident, attrs, bounds, kind } = param;
pub fn noop_flat_map_generic_param<T: MutVisitor>(mut param: GenericParam, vis: &mut T) -> SmallVec<[GenericParam; 1]> {
let GenericParam { id, ident, attrs, bounds, kind } = &mut param;
vis.visit_id(id);
vis.visit_ident(ident);
visit_thin_attrs(attrs, vis);
Expand All @@ -717,10 +713,8 @@ pub fn noop_visit_generic_param<T: MutVisitor>(param: &mut GenericParam, vis: &m
vis.visit_ty(ty);
}
}
}

pub fn noop_visit_generic_params<T: MutVisitor>(params: &mut Vec<GenericParam>, vis: &mut T){
visit_vec(params, |param| vis.visit_generic_param(param));
smallvec![param]
}

pub fn noop_visit_label<T: MutVisitor>(Label { ident }: &mut Label, vis: &mut T) {
Expand All @@ -734,7 +728,7 @@ fn noop_visit_lifetime<T: MutVisitor>(Lifetime { id, ident }: &mut Lifetime, vis

pub fn noop_visit_generics<T: MutVisitor>(generics: &mut Generics, vis: &mut T) {
let Generics { params, where_clause, span } = generics;
vis.visit_generic_params(params);
params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
vis.visit_where_clause(where_clause);
vis.visit_span(span);
}
Expand All @@ -750,7 +744,7 @@ pub fn noop_visit_where_predicate<T: MutVisitor>(pred: &mut WherePredicate, vis:
WherePredicate::BoundPredicate(bp) => {
let WhereBoundPredicate { span, bound_generic_params, bounded_ty, bounds } = bp;
vis.visit_span(span);
vis.visit_generic_params(bound_generic_params);
bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
vis.visit_ty(bounded_ty);
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
}
Expand Down Expand Up @@ -788,7 +782,7 @@ pub fn noop_visit_trait_ref<T: MutVisitor>(TraitRef { path, ref_id }: &mut Trait

pub fn noop_visit_poly_trait_ref<T: MutVisitor>(p: &mut PolyTraitRef, vis: &mut T) {
let PolyTraitRef { bound_generic_params, trait_ref, span } = p;
vis.visit_generic_params(bound_generic_params);
bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
vis.visit_trait_ref(trait_ref);
vis.visit_span(span);
}
Expand Down
1 change: 1 addition & 0 deletions src/libsyntax_ext/deriving/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ impl MultiItemModifier for ProcMacroDerive {
applied to a struct, enum, or union");
return Vec::new()
}
Annotatable::GenericParam(..) => panic!("unexpected annotatable")
};
match item.node {
ItemKind::Struct(..) |
Expand Down
10 changes: 5 additions & 5 deletions src/test/ui/conditional-compilation/cfg-generic-params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,21 @@ struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy;
//~^ ERROR only lifetime parameters can be used in this context

fn f_lt_no<#[cfg_attr(no, unknown)] 'a>() {} // OK
fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} //~ ERROR attribute `unknown` is currently unknown
fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} //~ ERROR cannot find attribute macro `unknown` in this scope
fn f_ty_no<#[cfg_attr(no, unknown)] T>() {} // OK
fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} //~ ERROR attribute `unknown` is currently unknown
fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} //~ ERROR cannot find attribute macro `unknown` in this scope

type FnNo = for<#[cfg_attr(no, unknown)] 'a> fn(); // OK
type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn();
//~^ ERROR attribute `unknown` is currently unknown
//~^ ERROR cannot find attribute macro `unknown` in this scope

type PolyNo = dyn for<#[cfg_attr(no, unknown)] 'a> Copy; // OK
type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy;
//~^ ERROR attribute `unknown` is currently unknown
//~^ ERROR cannot find attribute macro `unknown` in this scope

struct WhereNo where for<#[cfg_attr(no, unknown)] 'a> u8: Copy; // OK
struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy;
//~^ ERROR attribute `unknown` is currently unknown
//~^ ERROR cannot find attribute macro `unknown` in this scope

fn main() {
f_lt::<'static>();
Expand Down
Loading

0 comments on commit 83fdb8d

Please sign in to comment.