Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it illegal get `sizeof` non-static member of struct nested within class template?

In clang/llvm 3.6.2, the following code results in a compilation error when compiling with std=c++11:

template <typename T=void>
class bar
{
public:
    struct foo
    {
        int array[10];
    };

    int baz()
    {
        return sizeof(foo::array);
    }
};

int main(void)
{
    bar<> b;
    return b.baz();
}

Command line invocation:

$ clang++ -std=c++11 nonstatic.cpp -o nonstatic
nonstatic.cpp:12:28: error: invalid use of non-static data member 'array'
        return sizeof(foo::array);
                      ~~~~~^~~~~
nonstatic.cpp:20:14: note: in instantiation of member function
'bar<void>::baz' requested here
    return b.baz();

If I change bar to be no longer a template, as in

class bar
{
public:
    struct foo
    {
        int array[10];
    };

    int baz()
    {
        return sizeof(foo::array);
    }
};

int main(void)
{
    bar b;
    return b.baz();
}

then the code compiles cleanly. Of note, GCC 5.2.1 accepts both versions under std=c++11. Also of note, moving array into the enclosing class template body (but leaving it as a template) also results in clang accepting this.

Which behavior is correct vis-à-vis the standard? Is this a bug in GCC, clang, or both?

(I asked the same question on cfe-users, but so far have received no response).

like image 876
Bobby Moretti Avatar asked Mar 09 '16 20:03

Bobby Moretti


1 Answers

This is certainly a clang bug; the operand of your sizeof expression is an id-expression denoting a non-static data member, so [expr.prim.general]/13 holds. Here's a reduced example:

template<class T> struct M { int f() { return sizeof(T::x); } };
struct S { int x; };
int main() { return M<S>{}.f(); }

The bug exhibits when a dependent type member is accessed in an unevaluated context within a template instance method. Clang's implementation of the n2253 rule enabling the use of non-static data members in unevaluated context (and later improvements) appears rather fragile and to interact badly with templates; a similar (though distinct) bug is http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20151019/141535.html.

I can't find any indication that this has already been reported to Clang Bugzilla; you may want to open a new bug.

Depending on your situation, workarounds may include moving the static type and value calculations outside the instance method; notably even making baz a static member function is enough to persuade clang to accept your code.

like image 181
ecatmur Avatar answered Sep 19 '22 12:09

ecatmur