Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lang: allow the cfg attribute above the instructions #2339

Merged
merged 9 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ The minor version will be incremented upon a breaking change and the patch versi
- idl: Fix using `address` constraint with non-const expressions ([#3216](https://github.com/coral-xyz/anchor/pull/3216)).
- idl: Fix using full path types with `Program` ([#3228](https://github.com/coral-xyz/anchor/pull/3228)).
- lang: Use closures for `init` constraints to reduce the stack usage of `try_accounts` ([#2939](https://github.com/coral-xyz/anchor/pull/2939)).
- lang: Allow the `cfg` attribute above the instructions ([#2339](https://github.com/coral-xyz/anchor/pull/2339)).

### Breaking

Expand Down
7 changes: 4 additions & 3 deletions lang/syn/src/codegen/program/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use heck::SnakeCase;
use quote::quote;

pub fn generate(program: &Program) -> proc_macro2::TokenStream {
let mut accounts = std::collections::HashSet::new();
let mut accounts = std::collections::HashMap::new();

// Go through instruction accounts.
for ix in &program.ixs {
Expand All @@ -13,15 +13,16 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
"__client_accounts_{}",
anchor_ident.to_string().to_snake_case()
);
accounts.insert(macro_name);
accounts.insert(macro_name, ix.cfgs.as_slice());
}

// Build the tokens from all accounts
let account_structs: Vec<proc_macro2::TokenStream> = accounts
.iter()
.map(|macro_name: &String| {
.map(|(macro_name, cfgs)| {
let macro_name: proc_macro2::TokenStream = macro_name.parse().unwrap();
quote! {
#(#cfgs)*
pub use crate::#macro_name::*;
}
})
Expand Down
10 changes: 7 additions & 3 deletions lang/syn/src/codegen/program/cpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
let args: Vec<&syn::PatType> = ix.args.iter().map(|arg| &arg.raw_arg).collect();
let discriminator = gen_discriminator(SIGHASH_GLOBAL_NAMESPACE, name);
let ret_type = &ix.returns.ty.to_token_stream();
let ix_cfgs = &ix.cfgs;
let (method_ret, maybe_return) = match ret_type.to_string().as_str() {
"()" => (quote! {anchor_lang::Result<()> }, quote! { Ok(()) }),
_ => (
Expand All @@ -28,6 +29,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
};

quote! {
#(#ix_cfgs)*
pub fn #method_name<'a, 'b, 'c, 'info>(
ctx: anchor_lang::context::CpiContext<'a, 'b, 'c, 'info, #accounts_ident<'info>>,
#(#args),*
Expand Down Expand Up @@ -91,7 +93,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
}

pub fn generate_accounts(program: &Program) -> proc_macro2::TokenStream {
let mut accounts = std::collections::HashSet::new();
let mut accounts = std::collections::HashMap::new();

// Go through instruction accounts.
for ix in &program.ixs {
Expand All @@ -101,15 +103,17 @@ pub fn generate_accounts(program: &Program) -> proc_macro2::TokenStream {
"__cpi_client_accounts_{}",
anchor_ident.to_string().to_snake_case()
);
accounts.insert(macro_name);
let cfgs = &ix.cfgs;
accounts.insert(macro_name, cfgs.as_slice());
}

// Build the tokens from all accounts
let account_structs: Vec<proc_macro2::TokenStream> = accounts
.iter()
.map(|macro_name: &String| {
.map(|(macro_name, cfgs)| {
let macro_name: proc_macro2::TokenStream = macro_name.parse().unwrap();
quote! {
#(#cfgs)*
pub use crate::#macro_name::*;
}
})
Expand Down
2 changes: 2 additions & 0 deletions lang/syn/src/codegen/program/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
.parse()
.expect("Failed to parse ix method name in camel as `TokenStream`");
let discriminator = quote! { instruction::#ix_name_camel::DISCRIMINATOR };
let ix_cfgs = &ix.cfgs;

quote! {
#(#ix_cfgs)*
if data.starts_with(#discriminator) {
return __private::__global::#ix_method_name(
program_id,
Expand Down
2 changes: 2 additions & 0 deletions lang/syn/src/codegen/program/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
let variant_arm = generate_ix_variant(ix.raw_method.sig.ident.to_string(), &ix.args);
let ix_name_log = format!("Instruction: {ix_name}");
let ret_type = &ix.returns.ty.to_token_stream();
let cfgs = &ix.cfgs;
let maybe_set_return_data = match ret_type.to_string().as_str() {
"()" => quote! {},
_ => quote! {
Expand All @@ -113,6 +114,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
},
};
quote! {
#(#cfgs)*
#[inline(never)]
pub fn #ix_method_name<'info>(
__program_id: &Pubkey,
Expand Down
6 changes: 6 additions & 0 deletions lang/syn/src/codegen/program/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
.iter()
.map(|ix| {
let name = &ix.raw_method.sig.ident.to_string();
let ix_cfgs = &ix.cfgs;
let ix_name_camel =
proc_macro2::Ident::new(&name.to_camel_case(), ix.raw_method.sig.ident.span());
let raw_args: Vec<proc_macro2::TokenStream> = ix
Expand All @@ -34,10 +35,13 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
};

quote! {
#(#ix_cfgs)*
impl anchor_lang::Discriminator for #ix_name_camel {
const DISCRIMINATOR: &'static [u8] = #discriminator;
}
#(#ix_cfgs)*
impl anchor_lang::InstructionData for #ix_name_camel {}
#(#ix_cfgs)*
impl anchor_lang::Owner for #ix_name_camel {
fn owner() -> Pubkey {
ID
Expand All @@ -48,6 +52,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
// If no args, output a "unit" variant instead of a struct variant.
if ix.args.is_empty() {
quote! {
#(#ix_cfgs)*
/// Instruction.
#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct #ix_name_camel;
Expand All @@ -56,6 +61,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
}
} else {
quote! {
#(#ix_cfgs)*
/// Instruction.
#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct #ix_name_camel {
Expand Down
2 changes: 2 additions & 0 deletions lang/syn/src/idl/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub fn gen_idl_print_fn_program(program: &Program) -> TokenStream {
let name = ix.ident.to_string();
let name_pascal = format_ident!("{}", name.to_camel_case());
let ctx_ident = &ix.anchor_ident;
let cfgs = &ix.cfgs;

let docs = match &ix.docs {
Some(docs) if !no_docs => quote! { vec![#(#docs.into()),*] },
Expand Down Expand Up @@ -74,6 +75,7 @@ pub fn gen_idl_print_fn_program(program: &Program) -> TokenStream {

Ok((
quote! {
#(#cfgs)*
#idl::IdlInstruction {
name: #name.into(),
docs: #docs,
Expand Down
2 changes: 2 additions & 0 deletions lang/syn/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use syn::parse::{Error as ParseError, Parse, ParseStream, Result as ParseResult}
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::token::Comma;
use syn::Attribute;
use syn::Lit;
use syn::{
Expr, Generics, Ident, ItemEnum, ItemFn, ItemMod, ItemStruct, LitInt, PatType, Token, Type,
Expand Down Expand Up @@ -64,6 +65,7 @@ pub struct Ix {
pub raw_method: ItemFn,
pub ident: Ident,
pub docs: Option<Vec<String>>,
pub cfgs: Vec<Attribute>,
pub args: Vec<IxArg>,
pub returns: IxReturn,
// The ident for the struct deriving Accounts.
Expand Down
14 changes: 14 additions & 0 deletions lang/syn/src/parser/program/instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::parser::spl_interface;
use crate::{FallbackFn, Ix, IxArg, IxReturn, Overrides};
use syn::parse::{Error as ParseError, Result as ParseResult};
use syn::spanned::Spanned;
use syn::Attribute;

// Parse all non-state ix handlers from the program mod definition.
pub fn parse(program_mod: &syn::ItemMod) -> ParseResult<(Vec<Ix>, Option<FallbackFn>)> {
Expand All @@ -28,12 +29,14 @@ pub fn parse(program_mod: &syn::ItemMod) -> ParseResult<(Vec<Ix>, Option<Fallbac
let overrides = parse_overrides(&method.attrs)?;
let interface_discriminator = spl_interface::parse(&method.attrs);
let docs = docs::parse(&method.attrs);
let cfgs = parse_cfg(method);
let returns = parse_return(method)?;
let anchor_ident = ctx_accounts_ident(&ctx.raw_arg)?;
Ok(Ix {
raw_method: method.clone(),
ident: method.sig.ident.clone(),
docs,
cfgs,
args,
anchor_ident,
returns,
Expand Down Expand Up @@ -146,3 +149,14 @@ pub fn parse_return(method: &syn::ItemFn) -> ParseResult<IxReturn> {
)),
}
}

fn parse_cfg(method: &syn::ItemFn) -> Vec<Attribute> {
method
.attrs
.iter()
.filter_map(|attr| match attr.path.is_ident("cfg") {
true => Some(attr.to_owned()),
false => None,
})
.collect()
}
1 change: 1 addition & 0 deletions tests/misc/programs/misc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ no-idl = []
cpi = ["no-entrypoint"]
default = []
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
my-feature = []

[dependencies]
anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] }
Expand Down
4 changes: 4 additions & 0 deletions tests/misc/programs/misc/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -812,3 +812,7 @@ pub struct TestBoxedOwnerConstraint<'info> {
pub my_account: Box<Account<'info, Data>>,
pub program: Program<'info, Misc>,
}

#[cfg(feature = "my-feature")]
#[derive(Accounts)]
pub struct Empty {}
5 changes: 5 additions & 0 deletions tests/misc/programs/misc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,4 +396,9 @@ pub mod misc {
pub fn test_boxed_owner_constraint(_ctx: Context<TestBoxedOwnerConstraint>) -> Result<()> {
Ok(())
}

#[cfg(feature = "my-feature")]
pub fn only_my_feature(_ctx: Context<Empty>) -> Result<()> {
Ok(())
}
}
Loading