Repository: pytorch/pytorch

Issue:
OSX from Source ``error: call to 'recordTrace' is ambiguous``
```bash
torch/csrc/autograd/generated/VariableType.cpp:381:22: error: call to 'recordTrace' is ambiguous
      jit::Node *n = jit::tracer::recordTrace( "fill_", { self }, self );
                     ^~~~~~~~~~~~~~~~~~~~~~~~
/Users/hangzhang/pytorch/torch/csrc/jit/tracer.h:262:14: note: candidate function
inline Node* recordTrace(std::string op, std::initializer_list<Variable> inputs, const Variable& output) {
             ^
/Users/hangzhang/pytorch/torch/csrc/jit/tracer.h:265:14: note: candidate function
inline Node* recordTrace(std::string op, std::initializer_list<Variable> inputs, const std::tuple<Variable, Variable>& outputs) {
             ^
/Users/hangzhang/pytorch/torch/csrc/jit/tracer.h:268:14: note: candidate function
inline Node* recordTrace(std::string op, std::initializer_list<Variable> inputs, const std::tuple<Variable, Variable, Variable>& outputs) {
             ^
/Users/hangzhang/pytorch/torch/csrc/jit/tracer.h:271:14: note: candidate function
inline Node* recordTrace(std::string op, at::TensorList inputs, const Variable& output) {
```
when executing:
```bash
clang -Wno-unused-result -Wsign-compare -Wunreachable-code -DNDEBUG -g -fwrapv -O3 -Wall -I/anaconda/include -arch x86_64 -I/anaconda/include -arch x86_64 -I/usr/local/cuda/include -I/Users/hangzhang/pytorch -I/Users/hangzhang/pytorch/torch/csrc -I/Users/hangzhang/pytorch/torch/lib/pybind11/include -I/Users/hangzhang/pytorch/torch/lib/tmp_install/include -I/Users/hangzhang/pytorch/torch/lib/tmp_install/include/TH -I/Users/hangzhang/pytorch/torch/lib/tmp_install/include/THPP -I/Users/hangzhang/pytorch/torch/lib/tmp_install/include/THNN -I/Users/hangzhang/pytorch/torch/lib/tmp_install/include/ATen -I/anaconda/lib/python3.6/site-packages/numpy/core/include -I/Users/hangzhang/pytorch/torch/lib/tmp_install/include/THD -I/usr/local/cuda/include -I/Users/hangzhang/pytorch/torch/lib/tmp_install/include/THCUNN -I/anaconda/include/python3.6m -c torch/csrc/autograd/generated/python_nn_functions.cpp -o build/temp.macosx-10.7-x86_64-3.6/torch/csrc/autograd/generated/python_nn_functions.o -D_THP_CORE -std=c++11 -Wno-write-strings -fno-strict-aliasing -Wno-missing-braces -DWITH_NUMPY -DWITH_DISTRIBUTED -DWITH_CUDA -DCUDA_LIB_PATH=/usr/local/cuda/lib -DWITH_CUDNN
```


Discussion:
I'm seeing this as well as of last night. 

Its preceded by many warnings about `VariableVersion`:

```
    /private/var/folders/s1/_v14lsc56tv44hm304m07vn40000gq/T/pip-az42dap4-build/torch/csrc/autograd/variable_version.h:77:10: warning: class 'VariableVersion' was previously declared as a struct [-Wmismatched-tags]
      friend class VariableVersion;
```

But the first error is the one about `call to 'recordTrace' is ambiguous`. 

I went back, and I get a good install as late as commit 5989b05ecce4c41d69b4d41280a5ee47d2bb9fa4

Resolving patch:
diff --git a/tools/autograd/gen_variable_type.py b/tools/autograd/gen_variable_type.py
--- a/tools/autograd/gen_variable_type.py
+++ b/tools/autograd/gen_variable_type.py
@@ -116,7 +116,7 @@
 
 RECORD_TRACE = CodeTemplate("""\
 if (jit::tracer::isTracing({ ${tensor_args} })) {
-  jit::Node *n = jit::tracer::recordTrace( "${api_name}", { ${tensor_args} }, ${return_name} );
+  jit::Node *n = jit::tracer::recordTrace( "${api_name}", ${trace_inputs}, ${trace_outputs} );
   ${record_attributes}
 }
 """)
@@ -599,7 +599,41 @@ def emit_buffers(buffers):
         return res
 
     def emit_record_trace(env, declaration):
+
+        # Note [clang-802.0.42 tuple overload bug]
+        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+        # Originally, my plan for emit_$ecord_trace was to keep it as
+        # simple as possible, if at the expense of some somewhat ugly
+        # overloads.  So this meant we had a 'recordTrace' function
+        # with overloads like this:
+        #
+        #   recordTrace(..., const Variable& out)
+        #   recordTrace(..., const std::tuple<Variable, Variable>& out)
+        #
+        # Unfortunately, this triggers a bug in clang-802.0.42
+        # (widely used in macOS Sierra 10.12.6) wherein a Variable is
+        # implicitly convertible into a std::tuple<Variable, Variable>;
+        # a minimal repro can be seen below here:
+        #
+        #   #include <tuple>
+        #   struct T {};
+        #   void f(const std::tuple<T, T>&) {}
+        #   void g(T& x) { f(x); }
+        #
+        # To work around this bug, the code generator is a bit more
+        # complicated, and is taught how to handle this situation.
+
         local = {}
+
+        arguments = declaration['arguments']
+        tensor_args = [arg for arg in arguments if arg['simple_type'] in {'Tensor', 'TensorList'}]
+        if len(tensor_args) == 1 and tensor_args[0]['simple_type'] == 'TensorList':
+            # Special case for TensorList.  This only works when there
+            # is a single argument
+            local['trace_inputs'] = "cast_tensor_list({})".format(declaration['arguments'][0]['name'])
+        else:
+            local['trace_inputs'] = CodeTemplate("{ ${tensor_args} }").substitute(env)
+
         local['record_attributes'] = []
         for arg in declaration['arguments']:
             if arg['simple_type'] in {'Tensor', 'TensorList'}:
@@ -651,12 +685,18 @@ def emit_body(declaration):
 
         if declaration['inplace']:
             env['return_value'] = 'self'
-            env['return_name'] = 'self'
             env['result'] = 'static_cast<Variable&>(self)'
+            env['trace_outputs'] = '{ self }'
         else:
             env['return_value'] = '{}(std::move(ret))'.format(declaration['return_type'])
-            env['return_name'] = 'ret'
             env['result'] = 'std::get<0>(ret)' if len(declaration['returns']) > 1 else 'ret'
+            if len(declaration['returns']) > 1:
+                # NB: This won't work if we get heterogenous outputs
+                outs = ['std::get<{}>(ret)'.format(i)
+                        for i, v in enumerate(declaration['returns']) if v['type'] == 'Tensor']
+            else:
+                outs = ['ret']
+            env['trace_outputs'] = CodeTemplate("{ ${outs} }").substitute(outs=outs)
 
         if any(arg['simple_type'] in {'Generator', 'Storage'} for arg in arguments):
             env['record_trace'] = []


Test patch: