Q:

async/await vs. hand made continuations: is ExecuteSynchronously cleverly used?

I recently wrote the following code:
    Task<T> ExecAsync<T>( string connectionString, SqlCommand cmd, Func<SqlCommand, T> resultBuilder, CancellationToken cancellationToken = default(CancellationToken) )
    {
        var tcs = new TaskCompletionSource<T>();

        SqlConnectionProvider p;
        try
        {
            p = GetProvider( connectionString );
            Task<IDisposable> openTask = p.AcquireConnectionAsync( cmd, cancellationToken );
            openTask
                .ContinueWith( open =>
                {
                    if( open.IsFaulted ) tcs.SetException( open.Exception.InnerExceptions );
                    else if( open.IsCanceled ) tcs.SetCanceled();
                    else
                    {
                        var execTask = cmd.ExecuteNonQueryAsync( cancellationToken );
                        execTask.ContinueWith( exec =>
                        {
                            if( exec.IsFaulted ) tcs.SetException( exec.Exception.InnerExceptions );
                            else if( exec.IsCanceled ) tcs.SetCanceled();
                            else
                            {
                                try
                                {
                                    tcs.SetResult( resultBuilder( cmd ) );
                                }
                                catch( Exception exc ) { tcs.TrySetException( exc ); }
                            }
                        }, TaskContinuationOptions.ExecuteSynchronously );
                    }
                } )
                .ContinueWith( _ =>
                {
                    if( !openTask.IsFaulted ) openTask.Result.Dispose();
                }, TaskContinuationOptions.ExecuteSynchronously );
        }
        catch( Exception ex )
        {
            tcs.SetException( ex );
        }
        return tcs.Task;
    }

This works as intended. The same code written with async/await is (obviously) simpler:
async Task<T> ExecAsync<T>( string connectionString, SqlCommand cmd, Func<SqlCommand, T> resultBuilder, CancellationToken cancellationToken = default(CancellationToken) )
{
    SqlConnectionProvider p = GetProvider( connectionString );
    using( IDisposable openTask = await p.AcquireConnectionAsync( cmd, cancellationToken ) )
    {
        await cmd.ExecuteNonQueryAsync( cancellationToken );
        return resultBuilder( cmd );
    }
}

I had a quick look at the generated IL for the 2 versions: the async/await is bigger (not a surprise) but I was wondering if the async/await code generator analyses the fact that a continuation is actually synchronous to use TaskContinuationOptions.ExecuteSynchronously where it can... and I failed to find this in the IL generated code. 
If anyone knows this or have any clue about it, I'd be pleased to know!

A:

I was wondering if the async/await code generator analyses the fact
  that a continuation is actually synchronous to use
  TaskContinuationOptions.ExecuteSynchronously where it can... and I
  failed to find this in the IL generated code.

Whether await continuations - without ConfigureAwait(continueOnCapturedContext: false) - execute asynchronously or synchronously depends on the presence of a synchronization context on the thread which was executing your code when it hit the await point. If SynchronizationContext.Current != null, the further behavior depends on the implementation of SynchronizationContext.Post.
E.g., if you are on the main UI thread of a WPF/WinForms app, your continuations will be executed on the same thread, but still asynchronously, upon some future iteration of the message loop. It will be posted via SynchronizationContext.Post. That's provided the antecedent task has completed on a thread pool thread, or on a different synchronization context (e.g., Why a unique synchronization context for each Dispatcher.BeginInvoke callback?).
If the antecedent task has completed on a thread with the same synchronization context (e.g. a WinForm UI thread), the await continuation will be executed synchronously (inlined). SynchronizationContext.Post will not be used in this case.
In the absence of synchronization context, an await continuation will be executed synchronously on the same thread the antecedent task has completed on.
This is how it is different from your ContinueWith with TaskContinuationOptions.ExecuteSynchronously implementation, which doesn't care at all about the synchronization context of either initial thread or completion thread, and always executes the continuation synchronously (there are exceptions to this behavior, nonetheless).
You can use ConfigureAwait(continueOnCapturedContext: false) to get closer to the desired behavior, but its semantic is still different from TaskContinuationOptions.ExecuteSynchronously. In fact, it instructs the scheduler to not run a continuation on a thread with any synchronization context, so you may experience situations where ConfigureAwait(false) pushes the continuation to thread pool, while you might have been expecting a synchronous execution.
Also related: Revisiting Task.ConfigureAwait(continueOnCapturedContext: false).

