Idiomatic way to wait for concurrent futures

I need to launch several async functions concurrently and wait until they all return. What's the idiomatic way to do this?
For now, I have the approximately following code:

use futures::{join, executor::block_on}; // futures-preview
use std::future::Future;

async fn fut_1() {
async fn fut_2() {

async fn blocker(first: impl Future, second: impl Future) {
    join!(first, second)

fn main() {
    block_on(blocker(fut_1(), fut_2()));

But this requires async-await feature on futures-preview (for join), and this pulls in proc_macro_hack and friends, which I feel is... well, a hack. Is there any more acceptable way, or this is OK? Or do I do this entirely wrong?

proc_macro_hack isn't much of a hack, and the async-await feature might become active by default, so I would recommend just using join!. But if you really want to avoid it you could use the futures::future::join function instead.