Search code examples
c++clangc++17template-argument-deductioncompiler-bug

Clang claims that `member reference base type 'X' is not a structure or union`, but X is a structure template with deduced parameters


Consider following code:

template <typename T> struct X
{
    X(T) {}
    void foo() {}
};

template <typename T> struct Y
{
    int object = 0;

    void bar()
    {
        X(object).foo();
    }
};

Live on gcc.godbold.org

GCC 8.2 compiles it, while Clang 7 spits out following error:

<source>:13:18: error: member reference base type 'X' is not a structure or union
        X(object).foo();
        ~~~~~~~~~^~~~

This looks like a bug to me.

The conditions are very specific: If either structure is not a template, or if object is not a member variable, or if CTAD (class template argument deduction) is not involved, then Clang compiles the code as well.

What's going on here? Is it indeed a Clang bug?

And what's more important, how can I make the code compile with minimal changes, preferrably without getting rid of CTAD?


The only flag used is -std=c++17.

clang++ --version is

clang version 7.0.0 (tags/RELEASE_700/final 342594)
Target: x86_64-unknown-linux-gnu
Thread model: posix

Solution

  • Yes, this is clang bug see Class template argument deduction with deduced type fails when accessing member which says:

    Try to compile the following c++ program:

      template <class T>
      struct C {
        C(T) {}
        int a;
      };
    
      template <class T>
      int foo(T v) {
        return C{v}.a; // <----
      }
    
      int main() {
        foo(4);
      }
    

    The line marked above fails with the error:

    error: member reference base type 'C' is not a structure or union
        return (C{v}).a;
               ~~~~~~^~
    

    The bug report also specifies cases that do work, which may or may not be alternatives.

    Note that the following all work fine:

      template <class T>
      C<T> foo(T v) {
        return C{v};
      }
    

    and

    int foo(int v) {
        return C{v}.a;
      }
    

    and

      C{4}.a;
    

    I tried this also on a recent trunk build (trunk 346600)