Skip to content

Commit 9775ab4

Browse files
Fix contractimpl macro composability with third party macros (#1510)
### What Add a test vector that demonstrates a composability issue with third party function macros. Apple the existing filtering of which attributes get applied to the generated exported functions also to the generated spec constant. ### Why In #1427 I moved where the attributes were used as part of fixing another bug, and inadvertently moved the expansion of the attributes to the line before where the attributes are filtered. The filter ensures that only a specific set of attributes get applied to the generated code. The attributes still need to go through the filter for their use on the spec constant and it was an error on my part not to also move the filter. Close #1509
1 parent 07ef30e commit 9775ab4

8 files changed

Lines changed: 181 additions & 7 deletions

File tree

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ jobs:
124124
run: cargo-hack hack --feature-powerset --exclude-features docs build --target ${{ matrix.sys.target }}
125125
- if: "matrix.sys.cdylib-cross-compile-workaround"
126126
name: Build for native
127-
run: cargo-hack hack --feature-powerset --exclude-features docs rustc --workspace --exclude soroban-sdk-macros --crate-type lib --target ${{ matrix.sys.target }}
127+
run: cargo-hack hack --feature-powerset --exclude-features docs rustc --workspace --exclude soroban-sdk-macros --exclude proc_macros --crate-type lib --target ${{ matrix.sys.target }}
128128
- if: startsWith(matrix.sys.target, 'x86_64')
129129
name: Run tests
130130
run: cargo-hack hack --feature-powerset --ignore-unknown-features --features testutils --exclude-features docs test --target ${{ matrix.sys.target }}

Cargo.lock

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

soroban-sdk-macros/src/derive_spec_fn.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,12 @@ pub fn derive_fn_spec(
157157
return Err(quote! { #(#compile_errors)* });
158158
}
159159

160+
// Filter attributes to those that should be passed through to the generated code.
161+
let attrs = attrs
162+
.iter()
163+
.filter(|attr| pass_through_attr_to_gen_code(attr))
164+
.collect::<Vec<_>>();
165+
160166
let exported = if export {
161167
Some(quote! {
162168
#[doc(hidden)]
@@ -170,12 +176,6 @@ pub fn derive_fn_spec(
170176
None
171177
};
172178

173-
// Filter attributes to those that should be passed through to the generated code.
174-
let attrs = attrs
175-
.iter()
176-
.filter(|attr| pass_through_attr_to_gen_code(attr))
177-
.collect::<Vec<_>>();
178-
179179
// Generated code.
180180
Ok(quote! {
181181
#exported

tests/macros/Cargo.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "test_macros"
3+
description = "A test vector for testing the interactions of the soroban-sdk macros with third-party macros, validating that they are composable and compatible."
4+
version.workspace = true
5+
authors = ["Stellar Development Foundation <info@stellar.org>"]
6+
license = "Apache-2.0"
7+
edition = "2021"
8+
publish = false
9+
rust-version.workspace = true
10+
11+
[lib]
12+
crate-type = ["cdylib"]
13+
doctest = false
14+
15+
[dependencies]
16+
soroban-sdk = {path = "../../soroban-sdk"}
17+
proc_macros = {path = "./proc_macros"}
18+
19+
[dev-dependencies]
20+
soroban-sdk = {path = "../../soroban-sdk", features = ["testutils"]}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "proc_macros"
3+
description = "A collection of proc-macros used by the test_macros test vector to validate that the soroban-sdk macros are composable and compatible with a variety of other macros."
4+
version = "0.0.0"
5+
authors = ["Stellar Development Foundation <info@stellar.org>"]
6+
license = "Apache-2.0"
7+
edition = "2021"
8+
publish = false
9+
rust-version.workspace = true
10+
11+
[lib]
12+
proc-macro = true
13+
doctest = false
14+
15+
[dependencies]
16+
quote = "1.0"
17+
syn = { version = "2.0", features = ["full"] }
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/// A collection of proc-macros used by the test_macros test vector to validate that the
2+
/// soroban-sdk macros are composable and compatible with a variety of other macros.
3+
use proc_macro::TokenStream;
4+
use quote::quote;
5+
use syn::{parse_macro_input, ItemFn};
6+
7+
/// An attribute macro that expects to be used on a function.
8+
#[proc_macro_attribute]
9+
pub fn parse_item_fn(_metadata: TokenStream, input: TokenStream) -> TokenStream {
10+
let item = parse_macro_input!(input as ItemFn);
11+
quote! { #item }.into()
12+
}

tests/macros/src/lib.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// A test vector for testing the interactions of the soroban-sdk macros with third-party macros,
2+
// validating that they are composable and compatible.
3+
4+
#![no_std]
5+
use proc_macros::parse_item_fn;
6+
use soroban_sdk::{contract, contractimpl};
7+
8+
#[contract]
9+
pub struct Contract;
10+
11+
#[contractimpl]
12+
impl Contract {
13+
// Test that attribute macros that expect to be used on fns are composable with contractimpl.
14+
#[parse_item_fn]
15+
pub fn empty() {}
16+
}
17+
18+
#[cfg(test)]
19+
mod test {
20+
use soroban_sdk::Env;
21+
22+
use crate::{Contract, ContractClient};
23+
24+
#[test]
25+
fn test_empty() {
26+
let e = Env::default();
27+
let contract_id = e.register(Contract, ());
28+
let client = ContractClient::new(&e, &contract_id);
29+
30+
client.empty();
31+
}
32+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
{
2+
"generators": {
3+
"address": 1,
4+
"nonce": 0,
5+
"mux_id": 0
6+
},
7+
"auth": [
8+
[],
9+
[]
10+
],
11+
"ledger": {
12+
"protocol_version": 23,
13+
"sequence_number": 0,
14+
"timestamp": 0,
15+
"network_id": "0000000000000000000000000000000000000000000000000000000000000000",
16+
"base_reserve": 0,
17+
"min_persistent_entry_ttl": 4096,
18+
"min_temp_entry_ttl": 16,
19+
"max_entry_ttl": 6312000,
20+
"ledger_entries": [
21+
[
22+
{
23+
"contract_data": {
24+
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
25+
"key": "ledger_key_contract_instance",
26+
"durability": "persistent"
27+
}
28+
},
29+
[
30+
{
31+
"last_modified_ledger_seq": 0,
32+
"data": {
33+
"contract_data": {
34+
"ext": "v0",
35+
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
36+
"key": "ledger_key_contract_instance",
37+
"durability": "persistent",
38+
"val": {
39+
"contract_instance": {
40+
"executable": {
41+
"wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
42+
},
43+
"storage": null
44+
}
45+
}
46+
}
47+
},
48+
"ext": "v0"
49+
},
50+
4095
51+
]
52+
],
53+
[
54+
{
55+
"contract_code": {
56+
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
57+
}
58+
},
59+
[
60+
{
61+
"last_modified_ledger_seq": 0,
62+
"data": {
63+
"contract_code": {
64+
"ext": "v0",
65+
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
66+
"code": ""
67+
}
68+
},
69+
"ext": "v0"
70+
},
71+
4095
72+
]
73+
]
74+
]
75+
},
76+
"events": []
77+
}

0 commit comments

Comments
 (0)